sql >> Base de Datos >  >> NoSQL >> MongoDB

Encuentre un documento basado en una referencia al padre en el hijo

En realidad, la "mejor" forma de hacer esto es usar .aggregate() y $lookup para "unir" los datos y "filtrar" según las condiciones del partido. Esto es muy efectivo ya que MongoDB en realidad realiza todo esto en el "servidor" mismo, en comparación con la emisión de consultas "múltiples" como .populate() lo hace.

MovieModel.aggregate([
  { "$match": { "m_title": m_title } },
  { "$lookup": {
    "from": RankMovieModel.collection.name,
    "localField": "_id",
    "foreignField": "movie",
    "as": "rankings"
  }}
])

Si hay "muchas" clasificaciones, lo mejor es usar $unwind , que creará un documento para cada elemento de "clasificación" relacionado:

MovieModel.aggregate([
  { "$match": { "m_title": m_title } },
  { "$lookup": {
    "from": RankMovieModel.collection.name,
    "localField": "_id",
    "foreignField": "movie",
    "as": "rankings"
  }},
  { "$unwind": "$rankings" }
])

También hay un manejo especial aquí de cómo MongoDB se ocupa de "unir" documentos para evitar infringir el límite de BSON de 16 MB. De hecho, esto sucede cuando $unwind sigue directamente un $lookup etapa de canalización:

    {
        "$lookup" : {
            "from" : "rankmovies",
            "as" : "rankings",
            "localField" : "_id",
            "foreignField" : "movie",
            "unwinding" : {
                "preserveNullAndEmptyArrays" : false
            }
        }
    }

Así que el $unwind en realidad "desaparece" y en su lugar se "enrolla" en el $lookup como si se tratara de "una" operación. De esa forma, no creamos una "matriz" directamente dentro del documento principal, lo que haría que el tamaño excediera los 16 MB en casos extremos con muchos elementos "relacionados".

Si no tiene un MongoDB que admita $lookup ( MongoDB 3.2 mínimo ), entonces podría usar un "virtual" con .populate() en su lugar (requiere Mongoose 4.5.0 mínimo ). Pero tenga en cuenta que esto en realidad realiza "dos" consultas al servidor:

Primero agregue el "virtual" al esquema:

movieSchema.virtual("rankings",{
  "ref": "Movie",
  "localField": "_id",
  "foreignField": "movie"
});

Luego emita la consulta con .populate() :

MovieModel.find({ "m_title": m_title })
  .populate('rankings')
  .exec()