MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Trova un documento basato su un riferimento al genitore nel bambino

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()