Documento complejo agregado de Mongodb con búsquedas anidadas

Aug 19 2020

Tengo estas colecciones:

Sitios

{
  _id: ObjectId("5acdb8f65ea63a27c1facf86"),
  TemplateId: ObjectId("sdfsdfs34234234sdf"),
}

Plantillas

{
  _id: ObjectId("sdfsdfs34234234sdf"),
  Type: "Site",
  Name: "Site 1",
  Sections:[{
     id: ObjectId("8asdf89asd8f9sdf"),
     Header: "Header1",
     FieldItems: [
           {
            FieldId: ObjectId("jsd32423423423"),
            x: 1,
            y: 0
           },
           {
            FieldId: ObjectId("2342sdffafdasdfdfs"),
            x: 1,
            y: 1
           }
          ]
        },
       (...more sections...)
     ]
}

Campos

{
  _id: ObjectId("jsd32423423423"),
  Type: "Phone",
  Name: "Phone_Test"
},
{
  _id: ObjectId("2342sdffafdasdfdfs"),
  Type: "Numeric",
  Name: "Number_Test"
}
            

Soy nuevo en MongoDB, pero me he tomado un par de días leyendo preguntas y respuestas, así como documentación. Estoy usando MongoDB 4.2.6. Estoy tratando de devolver un resultado con el formato siguiente:

{
  id: ObjectId("5acdb8f65ea63a27c1facf86"),
  TemplateId: ObjectId("sdfsdfs34234234sdf"),
  Template: {
   id: ObjectId("sdfsdfs34234234sdf"),
   Type: "Site",
   Sections:[{
     id: ObjectId("8asdf89asd8f9sdf"),
     Header: "Header1",
     FieldItems: [
        {
          FieldId: ObjectId("jsd32423423423"),
          x: 1,
          y: 0,
          Field: {
              _id: ObjectId("jsd32423423423"),
              Type: "Phone",
              Name: "Phone_Test"
           }
        }, (...)]
      }]
}
  

Escribí una consulta agregada con búsquedas anidadas para llevarme principalmente allí, pero para que funcione, tuve que desenrollar Sections y FieldItems . No he descubierto una manera de hacer que las matrices estén como me gustaría. He intentado con el grupo pero tengo problemas con las matrices secundarias. Ni siquiera estoy seguro de si esta es la mejor manera de obtener los resultados que necesito:

db.getCollection("AppSites").aggregate(
[
    { 
        "$lookup" : { "from" : "AppTemplates", "let": {"template_id": "$TemplateId"},
            "pipeline": [
                { "$match": { "$expr": { "$eq" : ["$_id", "$$template_id"] } } }, { "$unwind": "$Sections"}, { "$unwind": "$Sections.FieldItems"}, { "$lookup": {
                        "from": "AppFields",
                        "let": {"field_id": "$Sections.FieldItems.FieldId"}, "pipeline": [ { "$match": { "$expr": { "$eq": ["$_id", "$$field_id"] } } }
                        ],
                        "as": "Sections.FieldItems.Field"
                    }
                }
            ],
            "as" : "Templates"
        }
    }
]
);

Respuestas

1 varman Aug 19 2020 at 00:21

Lo has hecho $unwinddos veces, así que necesitas usar dos $group.

{
  $group: { _id: { secId: "$_id",
      fId: "$Sections.id" }, Type: { $first: "$Type" }, Name: { $first: "$Name" }, Header: { $first: "$Sections.Header" }, fieldItems: { $push: "$Sections.FieldItems" } } }, { $group: {
    _id: "$_id.secId", Type: { $first: "$Type" }, Name: { $first: "$Name" }, Sections: { $push: {
        id: "$_id.fId", Header: "$Header",
        fieldItems: "$fieldItems"
      }
    }
  }
}
  1. Primer grupo: para agrupar objetos secundarios. Pero el tipo, el nombre y el encabezado deben configurarse como matriz principal y secundaria, respectivamente.
  2. Segundo grupo: para agrupar objetos principales. Obtenemos todos los campos independientes mientras agrupamos a los niños. Aquí solo tenemos que configurarlo en los ordenes correctos.

Parque infantil de trabajo Mongo

Nota: Cuando lo use $lookup, proporcionará una matriz. Pero hay algunos lugares en los que simplemente lo conviertes en objeto. No sé si se une a una relación de uno a uno o no. Si es así, puede usar el operador posicional en proyección o matrizElemAt