Агрегирование итоговых данных из вложенных документов в MongoDB

#arrays #mongodb #aggregation-framework

Вопрос:

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

По сути, каждый документ представляет собой запись о продажах, в которой содержится подробная информация о продажах и дополнительный документ / массив с количеством проданных товаров.

Я хотел бы составить краткое описание всех проданных товаров.

Таким образом, примером коллекции является:

 {
  non_relevant_1: "ABC",
  non_relevant_2: "DEF",
  items_array: {
    "item_1": 1,
    "item_2": 2,
    "item_3": 1,
    "item_4": 1
    }
},

{
  non_relevant_1: "HIJ",
  non_relevant_2: "KLM",
  items_array: {
    "item_1": 3,
    "item_2": 2,
    "item_3": 4
    }
}
 

Затем я хотел бы иметь возможность создать что-то вроде:

 {
items_array: {
    "item_1": 4,
    "item_2": 4,
    "item_3": 5,
    "item_4": 1
    }
}
 

Заранее большое спасибо.

Ответ №1:

Я думаю, вам нужно изменить свою схему, вы сохраняете данные в ключах. Операторы MongoDB не созданы для того, чтобы иметь неизвестные ключи, например, мы не можем группироваться по неизвестному ключу.Для этого мы делаем такие сложные и медленные вещи, как $objectToArray .

Кроме того, данные, которые вы хотите получить в качестве результатов, имеют ту же проблему.

Если вы посмотрите на запрос только посередине $unwind , и $group он будет нужен, с измененной схемой и запросом данных без данных в ключах.

Я имею в виду вместо

 items_array: {
    "item_1": 1,
    "item_2": 2,
    "item_3": 1,
    "item_4": 1
    }
 

Ваша коллекция должна быть такой(первая часть запроса делает это, изменяя вашу схему)

 items_array: [
    {"name" "item_1",
     "qty" : 1},
    {"name" "item_2",
     "qty" : 2},
    {"name" "item_3",
     "qty" : 1},
    {"name" "item_4",
     "qty" : 1}
    ]
 

Кроме того, результаты должны были содержать только известные ключи.
Может быть, причина, по которой ты застрял, заключается в этом.Вы сделаете все намного проще для себя.

Тестовый код здесь

Запрос (запрос работает для вашей схемы, но я сказал вам, что я думаю)

 db.collection.aggregate([
  {
    "$addFields": {
      "items_array": {
        "$map": {
          "input": {
            "$map": {
              "input": {
                "$objectToArray": "$items_array"
              },
              "as": "m",
              "in": [
                "$m.k",
                "$m.v"
              ]
            }
          },
          "as": "item",
          "in": {
            "name": {
              "$arrayElemAt": [
                "$item",
                0
              ]
            },
            "qty": {
              "$arrayElemAt": [
                "$item",
                1
              ]
            }
          }
        }
      }
    }
  },
  {
    "$unwind": {
      "path": "$items_array"
    }
  },
  {
    "$group": {
      "_id": "$items_array.name",
      "total-qty": {
        "$sum": "$items_array.qty"
      }
    }
  },
  {
    "$group": {
      "_id": null,
      "items_array": {
        "$push": {
          "$map": {
            "input": {
              "$map": {
                "input": {
                  "$objectToArray": "$ROOT"
                },
                "as": "m",
                "in": [
                  "$m.k",
                  "$m.v"
                ]
              }
            },
            "as": "i",
            "in": {
              "$arrayElemAt": [
                "$i",
                1
              ]
            }
          }
        }
      }
    }
  },
  {
    "$project": {
      "_id": 0
    }
  },
  {
    "$addFields": {
      "items_array": {
        "$arrayToObject": "$items_array"
      }
    }
  }
])
 

Комментарии:

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

2. я делал то же самое, потому что в языках программирования так часто добавляют данные по ключам, но в MongoDB это значительно усложняет задачу.