Det "bästa" sättet att göra detta är faktiskt snarare att använda .aggregate()
och $lookup
att "ansluta" till data och "filtrera" på matchvillkoren. Detta är mycket effektivt eftersom MongoDB faktiskt utför allt detta på "servern" själv, jämfört med att utfärda "flera" frågor som .populate()
gör.
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}}
])
Om det finns "många" rankningar är det bäst att använda $unwind
, som skapar ett dokument för varje relaterad "ranking"-post:
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}},
{ "$unwind": "$rankings" }
])
Det finns också en speciell hantering här av hur MongoDB hanterar att "ansluta" dokument för att undvika att bryta 16MB BSON-gränsen. Så i själva verket händer denna speciella sak när $unwind
följer direkt en $lookup
pipeline stage:
{
"$lookup" : {
"from" : "rankmovies",
"as" : "rankings",
"localField" : "_id",
"foreignField" : "movie",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
}
Så $unwind
faktiskt "försvinner" och istället "rullas upp" i
Om du inte har en MongoDB som stöder $lookup
( MongoDB 3.2 minunum ) då kan du använda en "virtuell" med .populate()
istället (kräver minst Mongoose 4.5.0 ). Men observera att detta faktiskt utför "två" frågor till servern:
Lägg först till det "virtuella" i schemat:
movieSchema.virtual("rankings",{
"ref": "Movie",
"localField": "_id",
"foreignField": "movie"
});
Ge sedan frågan med .populate()
:
MovieModel.find({ "m_title": m_title })
.populate('rankings')
.exec()