MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Aggregat $lookup gibt die ursprüngliche Array-Reihenfolge der Elemente nicht zurück

Dies ist "gewollt" von $lookup Implementierung. Was eigentlich passiert "unter der Haube" ist MongoDB intern konvertiert die Argumente in $lookup zum neuen expressiven mit $expr formatieren und $in . Sogar in Versionen vor diesem ausdrucksstarken Form implementiert wurde, die interne Mechanik für ein "Array von Werten" war wirklich ähnlich.

Die Lösung besteht hier darin, eine Kopie des ursprünglichen Arrays als Referenz für die Neuordnung von "joined" beizubehalten Artikel:

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

Oder durch das alte $lookup Verwendung:

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

Beide Varianten erzeugen dieselbe Ausgabe:

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

Das allgemeine Konzept besteht darin, $indexOfArray zu verwenden im Vergleich zur _id Wert aus "joined" Inhalt, um seinen "Index" zu finden Position im ursprünglichen Quellarray von "$Classes.ID" . Die unterschiedliche $lookup Syntaxvarianten haben unterschiedliche Ansätze, wie Sie auf diese Kopie zugreifen und wie Sie im Grunde rekonstruieren.

Der $sort legt natürlich die Reihenfolge der eigentlichen Dokumente fest, entweder innerhalb der Pipeline-Verarbeitung für die ausdrucksstarke Form oder über die exponierten Dokumente von $unwind . Wo Sie $unwind verwendet haben Sie würden dann $group zurück zum ursprünglichen Dokumentformular.

HINWEIS :Die Verwendungsbeispiele hier hängen von MongoDB 3.4 für $indexOfArray ab mindestens und das $$REMOVE stimmt mit MongoDB 3.6 überein, ebenso wie expressive $lookup .

Es gibt andere Ansätze zum Neuordnen des Arrays für frühere Versionen, aber diese werden ausführlicher in der Garantiereihenfolge der $in-Klausel von Does MongoDB demonstriert. Realistisch gesehen ist das absolute Minimum, das Sie derzeit als MongoDB-Produktionsversion ausführen sollten, die Version 3.4.

Siehe Supportrichtlinie unter MongoDB-Server für die vollständigen Details der unterstützten Releases und Enddaten.