Find A Document Based On A Reference To The Parent In The Child
Solution 1:
Actually the "best" way to do this is rather using .aggregate()
and $lookup
to "join" the data and "filter" on the match conditions. This is very effective since MongoDB actually performs all of this on the "server" itself, as compared to issuing "multiple" queries as .populate()
does.
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}}
])
Note: The
RankMovieModel.collection.name
is a nice way of getting the "underlying" collection name from theModel
registered with Mongoose. Since the operation is on the "server", MongoDB needs the "real collection name", so we can either "hardcode" that or just get it from the information registered on the Model itself. As is done here.
If there are "lots" of rankings, then you are best to use $unwind
, which will create a document for each related "rankings" item:
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}},
{ "$unwind": "$rankings" }
])
There is also a special handling here of how MongoDB deals with "joining" documents to avoid breaching the 16MB BSON limit. So in fact this special thing happens when $unwind
directly follows a $lookup
pipeline stage:
{
"$lookup" : {
"from" : "rankmovies",
"as" : "rankings",
"localField" : "_id",
"foreignField" : "movie",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
}
So the $unwind
actually "disappears" and instead is "rolled-up" into the $lookup
itself as if this were "one" operation. That way we do not create an "array" directly within the parent document which would cause the size to exceed 16MB in extreme cases with many "related" items.
If you do not have a MongoDB that supports $lookup
( MongoDB 3.2 minunum ) then you could use a "virtual" with .populate()
instead (requires Mongoose 4.5.0 minimum). But note this actually performs "two" queries to the server:
First add the "virtual" to the schema:
movieSchema.virtual("rankings",{
"ref": "Movie",
"localField": "_id",
"foreignField": "movie"
});
Then issue the query with .populate()
:
MovieModel.find({ "m_title": m_title })
.populate('rankings')
.exec()
Post a Comment for "Find A Document Based On A Reference To The Parent In The Child"