MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Encontrar um documento com base em uma referência ao pai na criança


Na verdade, a "melhor" maneira de fazer isso é usar .aggregate() e $lookup para "juntar" os dados e "filtrar" nas condições de jogo. Isso é muito eficaz, pois o MongoDB realmente executa tudo isso no próprio "servidor", em comparação com a emissão de consultas "múltiplas" como .populate() faz.
MovieModel.aggregate([
  { "$match": { "m_title": m_title } },
  { "$lookup": {
    "from": RankMovieModel.collection.name,
    "localField": "_id",
    "foreignField": "movie",
    "as": "rankings"
  }}
])

Se houver "muitos" rankings, é melhor usar $unwind , que criará um documento para cada item de "classificação" relacionado:
MovieModel.aggregate([
  { "$match": { "m_title": m_title } },
  { "$lookup": {
    "from": RankMovieModel.collection.name,
    "localField": "_id",
    "foreignField": "movie",
    "as": "rankings"
  }},
  { "$unwind": "$rankings" }
])

Há também um tratamento especial aqui de como o MongoDB lida com documentos de "junção" para evitar violar o limite de 16 MB de BSON. Então, na verdade, essa coisa especial acontece quando $unwind segue diretamente um $lookup estágio do encanamento:
    {
        "$lookup" : {
            "from" : "rankmovies",
            "as" : "rankings",
            "localField" : "_id",
            "foreignField" : "movie",
            "unwinding" : {
                "preserveNullAndEmptyArrays" : false
            }
        }
    }

Portanto, o $unwind na verdade "desaparece" e, em vez disso, é "enrolado" no $pesquisa si mesmo como se isso fosse "uma" operação. Dessa forma, não criamos um "array" diretamente no documento pai, o que faria com que o tamanho excedesse 16 MB em casos extremos com muitos itens "relacionados".

Se você não tiver um MongoDB que suporte $lookup ( MongoDB 3.2 minunum ), então você pode usar um "virtual" com .populate() em vez disso (requer Mongoose 4.5.0 mínimo ). Mas observe que isso realmente executa "dois" consultas ao servidor:

Primeiro adicione o "virtual" ao esquema:
movieSchema.virtual("rankings",{
  "ref": "Movie",
  "localField": "_id",
  "foreignField": "movie"
});

Em seguida, emita a consulta com .populate() :
MovieModel.find({ "m_title": m_title })
  .populate('rankings')
  .exec()