En fait, la "meilleure" façon de le faire est plutôt d'utiliser .aggregate()
et $lookup
pour "joindre" les données et "filtrer" sur les conditions de correspondance. C'est très efficace puisque MongoDB effectue tout cela sur le "serveur" lui-même, par rapport à l'émission de requêtes "multiples" comme .populate()
fait.
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}}
])
S'il y a "beaucoup" de classements, il est préférable d'utiliser $unwind
, qui créera un document pour chaque élément de "classement" associé :
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}},
{ "$unwind": "$rankings" }
])
Il y a aussi une gestion spéciale ici de la façon dont MongoDB traite les documents "joints" pour éviter de dépasser la limite de 16 Mo BSON. Donc, en fait, cette chose spéciale se produit lorsque $unwind
suit directement un $lookup
étape du pipeline :
{
"$lookup" : {
"from" : "rankmovies",
"as" : "rankings",
"localField" : "_id",
"foreignField" : "movie",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
}
Ainsi, le $unwind
en fait "disparaît" et est à la place "enroulé" dans le $lookup
comme s'il s'agissait d'"une" opération. De cette façon, nous ne créons pas de "tableau" directement dans le document parent, ce qui entraînerait une taille supérieure à 16 Mo dans les cas extrêmes avec de nombreux éléments "liés".
Si vous n'avez pas de MongoDB qui prend en charge $lookup
( MongoDB 3.2 minimum ) alors vous pouvez utiliser un "virtuel" avec .populate()
à la place (nécessite au minimum Mongoose 4.5.0 ). Mais notez que cela effectue en fait "deux" requêtes au serveur :
Ajoutez d'abord le "virtuel" au schéma :
movieSchema.virtual("rankings",{
"ref": "Movie",
"localField": "_id",
"foreignField": "movie"
});
Lancez ensuite la requête avec .populate()
:
MovieModel.find({ "m_title": m_title })
.populate('rankings')
.exec()