Mongodb агрегирует сложный документ с вложенными поисковыми системами

#mongodb

#mongodb

Вопрос:

У меня есть эти коллекции:

Сайты

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

Шаблоны

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

Поля

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

Я новичок в MongoDB, но потратил пару дней на чтение вопросов и ответов, а также документации. Я использую MongoDB 4.2.6. Я пытаюсь вернуть результат, отформатированный следующим образом:

 {
  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"
           }
        }, (...)]
      }]
}
  
  

Я написал агрегированный запрос с вложенными поисковыми системами, чтобы в основном попасть туда, но чтобы заставить его работать, мне пришлось развернуть разделы и элементы полей. Я не нашел способа привести массивы к тому, как я их хотел бы. Я пробовал группировать, но возникли проблемы с вложенными массивами. Я даже не уверен, что это лучший способ получить нужные мне результаты:

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

Ответ №1:

Вы сделали это $unwind два раза, поэтому вам нужно использовать два $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. Первая группа — для группировки дочерних объектов. Но тип, имя и заголовок должны быть установлены в родительский и дочерний массив соответственно.
  2. Вторая группа — для группировки родительских объектов. Мы получаем все отдельные поля при группировании дочерних. Здесь нам просто нужно настроить его в правильном порядке.

Рабочая игровая площадка Mongo

Примечание: При использовании $lookup он предоставит массив. Но есть некоторые места, где вы просто создаете его как объект. Я не знаю, являются ли ваши соединения взаимно однозначными или нет. Если это так, вы можете использовать позиционный оператор в проекции или arrayElemAt