sql >> Database >  >> NoSQL >> MongoDB

Aggregate $lookup retourneert de oorspronkelijke arrayvolgorde van elementen niet

Dit is "door het ontwerp" van de $lookup implementatie. Wat eigenlijk gebeurt "onder de motorkap" is MongoDB intern converteert de argumenten in de $lookup naar de nieuwe expressieve formaat met behulp van $expr en $in . Zelfs in eerdere versies dan wanneer dit expressief vorm is geïmplementeerd, de interne mechanica voor een "array van waarden" was eigenlijk hetzelfde.

De oplossing hier is om een ​​kopie van de originele array te behouden als referentie voor het opnieuw ordenen van de "joined" artikelen:

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

Of door de legacy $lookup gebruik:

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 produceren dezelfde 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"
                }
        ]
}

Het algemene concept is om $indexOfArray . te gebruiken in vergelijking met de _id waarde van de "joined" inhoud om zijn "index" te vinden positie in de originele bronarray van "$Classes.ID" . De verschillende $lookup syntaxisvarianten hebben verschillende manieren om toegang te krijgen tot deze kopie en hoe je in principe reconstrueert.

De $sort bepaalt natuurlijk de volgorde van daadwerkelijke documenten, ofwel binnen de pijplijnverwerking voor de expressieve vorm, of via de blootgestelde documenten van $unwind . Waar je $unwind hebt gebruikt je zou dan $group terug naar het originele documentformulier.

OPMERKING :De gebruiksvoorbeelden hier zijn afhankelijk van MongoDB 3.4 voor de $indexOfArray tenminste en de $$REMOVE komt overeen met MongoDB 3.6 zoals de expressieve $lookup .

Er zijn andere benaderingen om de array opnieuw te ordenen voor eerdere releases, maar deze worden in meer detail gedemonstreerd op de garantievolgorde $in-clausule van Does MongoDB. Realistisch gezien is het absolute minimum dat u momenteel zou moeten gebruiken als een productie MongoDB-versie de 3.4-release.

Zie Ondersteuningsbeleid onder MongoDB-server voor de volledige details van ondersteunde releases en einddatums.




  1. 3 manieren om een ​​index te verbergen voor het queryplan in MongoDB

  2. Hoe start je een mongodb-shell in een docker-container?

  3. Slechte prestaties van opzoekaggregatie

  4. MongoDB:alleen documenten ophalen die in de afgelopen 24 uur zijn gemaakt?