sql >> Databasteknik >  >> NoSQL >> MongoDB

Aggregate $lookup returnerar inte elementens ursprungliga arrayordning

Detta är "by design" av $lookup genomförande. Vad egentligen händer "under huven" är MongoDB internt konverterar argumenten i $lookup till den nya expressiva formatera med $expr och $in . Även i versioner före när detta expressivt form implementerades, den interna mekaniken för en "array of values" var verkligen likadant.

Lösningen här är att behålla en kopia av den ursprungliga arrayen som referens för att ordna om "joined" föremål:

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

Eller genom den äldre $lookup användning:

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

Båda varianterna ger samma utdata:

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

Det allmänna konceptet är att använda $indexOfArray i jämförelse med _id värde från "joined" innehåll för att hitta det är "index" position i den ursprungliga källarrayen från "$Classes.ID" . De olika $lookup syntaxvarianter har olika tillvägagångssätt för hur du kommer åt denna kopia och hur du i princip rekonstruerar.

$sort anger naturligtvis ordningen för faktiska dokument, antingen inne i pipeline-bearbetningen för den uttrycksfulla formen, eller via de exponerade dokumenten av $unwind . Där du använde $unwind du skulle då $group tillbaka till det ursprungliga dokumentformuläret.

OBS :Användningsexemplen här beror på MongoDB 3.4 för $indexOfArray åtminstone och $$REMOVE anpassar sig till MongoDB 3.6 liksom expressiva $lookup .

Det finns andra tillvägagångssätt för att beställa om arrayen för tidigare utgåvor, men dessa visas mer i detalj på Does MongoDB:s garantiordning för $in-klausulen. Realistiskt sett är det absoluta minimum du för närvarande bör köra som en produktionsversion av MongoDB version 3.4.

Se Supportpolicy under MongoDB Server för fullständig information om utgåvor som stöds och slutdatum.




  1. Mongodb hitta inuti sub array

  2. MongoDB samlad fråga med PHP-drivrutin

  3. JedisPoolConfig kan inte tilldelas till GenericObjectPoolConfig

  4. Mongoose:CastError:Cast to ObjectId misslyckades för värdet [object Object] vid sökväg _id