MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Trouver un document basé sur une référence au parent dans l'enfant

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