In realtà il modo "migliore" per farlo è piuttosto usare .aggregate()
e $lookup
per "unire" i dati e "filtrare" sulle condizioni di corrispondenza. Questo è molto efficace poiché MongoDB esegue effettivamente tutto ciò sul "server" stesso, rispetto all'emissione di query "multiple" come .populate()
fa.
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}}
])
Se ci sono "molte" classifiche, allora è meglio usare $unwind
, che creerà un documento per ogni voce di "classifica" correlata:
MovieModel.aggregate([
{ "$match": { "m_title": m_title } },
{ "$lookup": {
"from": RankMovieModel.collection.name,
"localField": "_id",
"foreignField": "movie",
"as": "rankings"
}},
{ "$unwind": "$rankings" }
])
C'è anche una gestione speciale qui di come MongoDB gestisce i documenti di "unione" per evitare di violare il limite di 16 MB BSON. Quindi in effetti questa cosa speciale accade quando $unwind
segue direttamente un $lookup
fase della pipeline:
{
"$lookup" : {
"from" : "rankmovies",
"as" : "rankings",
"localField" : "_id",
"foreignField" : "movie",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
}
}
}
Quindi $unwind
in realtà "scompare" e invece viene "arrotolato" nel $lookup
stesso come se questa fosse "una" operazione. In questo modo non creiamo un "array" direttamente all'interno del documento principale che farebbe superare la dimensione di 16 MB in casi estremi con molti elementi "correlati".
Se non hai un MongoDB che supporti $lookup
( MongoDB 3.2 minuti ) allora potresti usare un "virtuale" con .populate()
invece (richiede Mongoose 4.5.0 minimo ). Ma tieni presente che in realtà esegue "due" query al server:
Per prima cosa aggiungi il "virtuale" allo schema:
movieSchema.virtual("rankings",{
"ref": "Movie",
"localField": "_id",
"foreignField": "movie"
});
Quindi invia la query con .populate()
:
MovieModel.find({ "m_title": m_title })
.populate('rankings')
.exec()