MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

L'agrégat $lookup ne renvoie pas l'ordre du tableau d'origine des éléments

C'est "de par la conception" du $lookup la mise en oeuvre. Qu'est-ce en fait se passe "sous le capot" est MongoDB interne convertit les arguments dans le $lookup au nouveau expressif formater en utilisant $expr et $in . Même dans les versions antérieures à ce moment expressif form a été implémenté, la mécanique interne pour un "tableau de valeurs" était vraiment la même chose.

La solution ici est de conserver une copie du tableau d'origine comme référence pour réorganiser les "joints" articles :

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 par l'ancien $lookup utilisation :

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

Les deux variantes produisent le même résultat :

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

Le concept général étant d'utiliser $indexOfArray en comparaison avec le _id valeur du "joint" contenu pour trouver son "index" position dans le tableau source d'origine à partir de "$Classes.ID" . Les différents $lookup les variantes de syntaxe ont des approches différentes pour accéder à cette copie et comment vous reconstruisez fondamentalement.

Le $sort définit bien sûr l'ordre des documents réels, soit à l'intérieur du pipeline de traitement pour la forme expressive, ou via les documents exposés de $unwind . Où vous avez utilisé $unwind vous feriez alors $group retour au formulaire de document d'origine.

REMARQUE :Les exemples d'utilisation ici dépendent de MongoDB 3.4 pour le $indexOfArray au moins et le $$REMOVE s'aligne sur MongoDB 3.6 comme le ferait le expressif $lookup .

Il existe d'autres approches pour réorganiser le tableau pour les versions précédentes, mais celles-ci sont présentées plus en détail dans l'ordre de garantie de la clause $in de Does MongoDB. De manière réaliste, le strict minimum que vous devriez actuellement exécuter en tant que version de production de MongoDB est la version 3.4.

Voir Politique d'assistance sous Serveur MongoDB pour plus de détails sur les versions prises en charge et les dates de fin.