问题
I am performing joins in mongodb using $lookup, now i am facing a problem here. I have two collections first one to contains users all bookmarks brands and the second one contains all details about the brands.Now i am trying to return all brands details bookmarked by the user.
user_bookmarked Collection
{"mobile_no": "8971740148", "brands": ["5829c1df334d40e20e1d1c19", "5829c1df334d40e20e1d1c20", "5829c1df334d40e20e1d1c21"]}
brands Collection
{"_id": ObjectId("5829c1df334d40e20e1d1c19"), "brand_name": "Versace"}
{"_id": ObjectId("5829c1df334d40e20e1d1c20"), "brand_name": "Lee Cooper"}
{"_id": ObjectId("5829c1df334d40e20e1d1c21"), "brand_name": "Levis"}
My aggregation pipeline code is given below
{ $match: { mobile_no: mobile_no }},
{ $unwind: { path: "$brands", includeArrayIndex: "brandsposition"}},
{ $lookup: {from: "brands",localField: "brands",foreignField: "_id",as: "user_bookmarks"}},
Now the problem i am facing is that above code doesn't return anything as i am storing brands ids as string in my user_bookmarked collection but not as ObjectId so nothing is being returned. Now can anyone please tell me how can i change field type inside aggregation query.
Second thing i want to ask please tell me when using $lookup then does mongodb utilises index on foreign_field or not. Because i ran above aggregation pipeline with explain: true but i don't found any index that was utilised by above query i got this returned by the output.
db.user_bookmarked.runCommand('aggregate', {pipeline: [{ $match: { mobile_no: mobile_no }},
{ $unwind: { path: "$brands", includeArrayIndex: "brandsposition"}},
{ $lookup: {from: "brands",localField: "brands",foreignField: "_id",as: "user_bookmarks"}}], explain: true})
{
"waitedMS" : NumberLong(0),
"stages" : [
{
"$cursor" : {
"query" : {
"mobile_no" : "8971740148"
},
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.restaurants",
"indexFilterSet" : false,
"parsedQuery" : {
"mobile_no" : {
"$eq" : "8971740148"
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"mobile_no" : {
"$eq" : "8971740148"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
}
}
},
{
"$unwind" : {
"path" : "$brands",
"includeArrayIndex" : "brandsposition"
}
},
{
"$lookup" : {
"from" : "brands",
"as" : "user_bookmarks",
"localField" : "brands",
"foreignField" : "_id"
}
}
],
"ok" : 1
}
Now can anyone please help me out of here i have searched about both of this thing which is how to change type of field inside aggregation and does $lookup utilises indexes but Haven't found anything useful please help me out of here guys it would be really appreciable.
回答1:
You cannot convert the string to a object Id within the pipeline, you'll have to go though each document and convert it manually, using something like (you shouldnt be storing a mix match of types anyway, so it's probably worth updating in the long run):
how to convert string to numerical values in mongodb
as for does $lookup use index, If you look at the stats from this blog you'll see that indexes are used -
http://guyharrison.squarespace.com/blog/2016/7/4/join-performance-in-mongodb-32-using-lookup.html
回答2:
Try casting your brands to ObjectIds before your population:
user_bookmarked.brands.map((brand) => return mongoose.Types.ObjectId(brand) )
But you really should consider storing them as refs instead, your model should look something like:
const user_bookmarked = new mongoose.Schema({
...
brands: [{type: mongoose.Schema.Types.ObjectId, ref: 'Brands'}],
...
})
This way they will be ObjectIds from the start.!
Regarding the second question this post explains it I think: join-performance-in-mongodb-32-using-lookup
来源:https://stackoverflow.com/questions/41042482/change-type-of-field-inside-mongodb-aggregation-and-does-lookup-utilises-index