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

Aggregate $lookup non restituisce l'ordine dell'array originale degli elementi

Questo è "in base alla progettazione" di $lookup implementazione. Cosa in realtà succede "sotto il cofano" è MongoDB interno converte gli argomenti nel $lookup al nuovo espressivo formattare utilizzando $expr e $in . Anche nelle versioni precedenti a quando questo espressivo modulo è stato implementato, la meccanica interna per un "array di valori" era davvero lo stesso.

La soluzione qui è mantenere una copia dell'array originale come riferimento per riordinare il "unito" articoli:

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"
  }}
])

O dall'eredità $lookup utilizzo:

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" }
  }}
])

Entrambe le varianti producono lo stesso output:

{
        "_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"
                }
        ]
}

Il concetto generale è usare $indexOfArray rispetto a _id valore da "unito" contenuto per trovarlo è "indice" posizione nell'array di origine originale da "$Classes.ID" . Il diverso $lookup le varianti di sintassi hanno approcci diversi al modo in cui accedi a questa copia e come sostanzialmente ricostruisci.

Il $sort ovviamente imposta l'ordine dei documenti effettivi, essendo all'interno dell'elaborazione della pipeline per la forma espressiva, o tramite i documenti esposti di $unwind . Dove hai usato $unwind quindi $group torna al modulo del documento originale.

NOTA :Gli esempi di utilizzo qui dipendono da MongoDB 3.4 per $indexOfArray almeno e il $$REMOVE si allinea con MongoDB 3.6 come farebbe il espressivo $lookup .

Esistono altri approcci per riordinare l'array per le versioni precedenti, ma questi sono dimostrati in modo più dettagliato nell'ordine di garanzia della clausola $in di Does MongoDB. Realisticamente il minimo indispensabile che dovresti attualmente eseguire come versione MongoDB di produzione è la versione 3.4.

Consulta le Norme di supporto in Server MongoDB per i dettagli completi delle versioni supportate e delle date di fine.