sql >> Base de Datos >  >> NoSQL >> MongoDB

Agregado $búsqueda no devuelve el orden original de la matriz de elementos

Esto es "por diseño" de $lookup implementación. ¿Qué realmente sucede "bajo el capó" es MongoDB interno convierte los argumentos en el $lookup al nuevo expresivo formatear usando $expr y $in . Incluso en versiones anteriores a cuando esta expresiva se implementó el formulario, la mecánica interna para una "matriz de valores" era realmente lo mismo.

La solución aquí es mantener una copia de la matriz original como referencia para reordenar los "unidos" artículos:

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 por el heredado $lookup uso:

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

Ambas variantes producen el mismo resultado:

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

El concepto general es usar $indexOfArray en comparación con el _id valor de "joined" content para encontrar su "index" posición en la matriz fuente original de "$Classes.ID" . Los diferentes $lookup las variantes de sintaxis tienen diferentes enfoques sobre cómo acceder a esta copia y cómo reconstruyes básicamente.

El $sort por supuesto, establece el orden de los documentos reales, ya sea estando dentro del proceso de canalización por la forma expresiva, o a través de los documentos expuestos de $unwind . Donde usaste $unwind entonces $group volver al formulario del documento original.

NOTA :Los ejemplos de uso aquí dependen de MongoDB 3.4 para el $indexOfArray al menos y el $$REMOVE se alinea con MongoDB 3.6 como lo haría el expresivo $lookup .

Hay otros enfoques para reordenar la matriz para versiones anteriores, pero estos se muestran con más detalle en el orden de garantía de la cláusula $in de Does MongoDB. Siendo realistas, lo mínimo que debería ejecutar actualmente como una versión de producción de MongoDB es la versión 3.4.

Ver Política de soporte en Servidor MongoDB para obtener los detalles completos de las versiones admitidas y las fechas de finalización.