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

Agregar $ lookup não retorna a ordem original da matriz dos elementos


Isso é "por design" do $lookup implementação. O que na verdade acontece "sob o capô" é MongoDB interno converte os argumentos no $lookup para o novo expressivo formato usando $expr e $in . Mesmo em versões anteriores a quando este expressivo formulário foi implementado, a mecânica interna para uma "matriz de valores" realmente era muito o mesmo.

A solução aqui é manter uma cópia do array original como referência para reordenar o "joined" Unid:
collection.aggregate([
  {"$match": {"_id": ObjectId("5c781752176c512f180048e3") }},
  {"$lookup": {
    "from": "collection2",
    "let": { "classIds": "$Classes.ID" },
    "pipeline": [
      { "$match": {
        "$expr": { "$in": [ "$_id", "$$classIds" ] }
      }},
      { "$addFields": {
        "sort": {
          "$indexOfArray": [ "$$classIds", "$_id" ]
        }
      }},
      { "$sort": { "sort": 1 } },
      { "$addFields": { "sort": "$$REMOVE" }}
    ],
    "as": "results"
  }}
])

Ou pelo legado $lookup uso:
collection.aggregate([
  {"$match": {"_id": ObjectId("5c781752176c512f180048e3") }},
  {"$lookup": {
    "from": "collection2",
    "localField": "Classes.ID",
    "foreignField": "_id",
    "as": "results"
  }},
  { "$unwind": "$results" },
  { "$addFields": {
    "sort": {
      "$indexOfArray": [ "$Classes.ID", "$results._id" ]
    }
  }},
  { "$sort": { "_id": 1, "sort": 1 } },
  { "$group": {
    "_id": "$_id",
    "Name": { "$first": "$Name" },
    "Classes": { "$first": "$Classes" },
    "results": { "$push": "$results" }
  }}
])

Ambas as variantes produzem a mesma saída:
{
        "_id" : ObjectId("5c781752176c512f180048e3"),
        "Name" : "Pedro",
        "Classes" : [
                {
                        "ID" : ObjectId("5c7af2b2f6f6e47c9060d7ce")
                },
                {
                        "ID" : ObjectId("5c7af2bcf6f6e47c9060d7cf")
                },
                {
                        "ID" : ObjectId("5c7af2aaf6f6e47c9060d7cd")
                }
        ],
        "results" : [
                {
                        "_id" : ObjectId("5c7af2b2f6f6e47c9060d7ce"),
                        "variable1" : "B"
                },
                {
                        "_id" : ObjectId("5c7af2bcf6f6e47c9060d7cf"),
                        "variable1" : "C"
                },
                {
                        "_id" : ObjectId("5c7af2aaf6f6e47c9060d7cd"),
                        "variable1" : "A"
                }
        ]
}

O conceito geral é usar $indexOfArray em comparação com o _id valor do "unido" conteúdo para encontrar seu "índice" posição na matriz de origem original de "$Classes.ID" . Os diferentes $lookup as variantes de sintaxe têm abordagens diferentes de como você acessa esta cópia e como você basicamente reconstrói.

O $sort é claro que define a ordem dos documentos reais, seja dentro do processamento do pipeline para a forma expressiva, ou através dos documentos expostos de $unwind . Onde você usou $unwind você então $group de volta ao formulário do documento original.

OBSERVAÇÃO :Os exemplos de uso aqui dependem do MongoDB 3.4 para o $indexOfArray pelo menos e o $$REMOVE se alinha com o MongoDB 3.6 como faria o expressivo $lookup .

Existem outras abordagens para reordenar o array para versões anteriores, mas elas são demonstradas com mais detalhes na ordem de garantia da cláusula $in do MongoDB. Realisticamente, o mínimo que você deve estar executando atualmente como uma versão de produção do MongoDB é a versão 3.4.

Consulte a Política de suporte em Servidor MongoDB para obter os detalhes completos das versões com suporte e datas de término.