Eigenlijk is de "beste" manier om dit te doen eerder het gebruik van .aggregate()
en $lookup
om de gegevens "aan te sluiten" en te "filteren" op de wedstrijdvoorwaarden. Dit is zeer effectief omdat MongoDB dit allemaal op de "server" zelf uitvoert, in vergelijking met het uitgeven van "meerdere" queries als .populate()
doet.
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}}
])
Als er "veel" ranglijsten zijn, kunt u het beste
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}},
{ "$unwind": "$rankings" }
])
Er is hier ook een speciale behandeling van hoe MongoDB omgaat met "samengevoegde" documenten om te voorkomen dat de BSON-limiet van 16 MB wordt overschreden. Dus in feite gebeurt dit speciale wanneer $unwind
volgt direct een $lookup
pijplijnfase:
{
"$lookup" : {
"from" : "rankmovies",
"as" : "rankings",
"localField" : "_id",
"foreignField" : "movie",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
}
Dus de $unwind
eigenlijk "verdwijnt" en wordt in plaats daarvan "opgerold" in de $opzoeken
zichzelf alsof dit "één" operatie was. Op die manier creëren we geen "array" rechtstreeks in het bovenliggende document, waardoor de grootte in extreme gevallen met veel "gerelateerde" items groter zou zijn dan 16 MB.
Als u geen MongoDB heeft die $lookup
( MongoDB 3.2 minimum ) dan zou je een "virtuele" kunnen gebruiken met .populate()
in plaats daarvan (vereist Mongoose 4.5.0 minimum ). Maar merk op dat dit feitelijk "twee" uitvoert vragen naar de server:
Voeg eerst de "virtuele" toe aan het schema:
movieSchema.virtual("rankings",{
"ref": "Movie",
"localField": "_id",
"foreignField": "movie"
});
Geef vervolgens de query op met .populate()
:
MovieModel.find({ "m_title": m_title })
.populate('rankings')
.exec()