MongoDB несколько вложенных групп - PullRequest
1 голос
/ 13 июня 2019

У меня есть документы в mongodb, как это

{
  _id: "5cfed55974c7c52ecc33ada8",
  name: "Garona",
  realm: "Blackrock",
  faction: "Horde",
  race: "Orc",
  class: "Rogue",
  guild: "",
  level: 33,
  lastSeen: "2019-06-10T00:00:00.000Z",
  __v: 0
},
{
  _id: "5cfed55974c7c52ecc33ade8",
  name: "Muradin",
  realm: "Alleria",
  faction: "Alliance",
  race: "Dwarf",
  class: "Warrior",
  guild: "Stormstout Brewing Co",
  level: 42,
  lastSeen: "2019-06-11T00:00:00.000Z",
  __v: 0
}

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

{
  $group: {
    _id: {
      classes: '1',
      class: '$class'
    },
    total: { $sum: 1 }
  }
},
{
  $group: {
    _id: '$_id.classes',
    total: { $sum: '$total' },
    classes: {
      $push: {
        class: '$_id.class',
        total: '$total'
      }
    }
  }
}

Который производит что-то вроде этого

{
  _id: "1",
  total: 40,
  classes: [
    {
      class: "Warrior",
      total: 17
    },
    {
      class: "Rogue",
      total: 23
    }
}

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

{
  _id: "1",
  total: 40,
  classes: [
    {
      class: "Warrior",
      total: 17
    },
    {
      class: "Rogue",
      total: 23
    },
  factions: [
    {
      faction: "Alliance",
      total: 27
    },
    {
      faction: "Horde",
      total: 13
    }
}

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

1 Ответ

2 голосов
/ 13 июня 2019

Это можно сделать с помощью этапа агрегации $ facet

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

Я лишь слегка изменил ваш исходный конвейер, а затем просто скопировал его для «фракций»поле.

Последние 3 этапа в моем решении на самом деле не нужны, они просто немного очищают вывод.

Вероятно, вы можете взять его отсюда, удачи.

db.collection.aggregate([
  {
    "$facet": {
      "classes": [
        {
          $group: {
            _id: "$class",
            total: {
              $sum: 1
            }
          }
        },
        {
          $group: {
            _id: null,
            total: {
              $sum: "$total"
            },
            "classes": {
              $push: {
                class: "$_id",
                total: "$total"
              }
            }
          }
        }
      ],
      "factions": [
        {
          $group: {
            _id: "$faction",
            total: {
              $sum: 1
            }
          }
        },
        {
          $group: {
            _id: null,
            total: {
              $sum: "$total"
            },
            "factions": {
              $push: {
                faction: "$_id",
                total: "$total"
              }
            }
          }
        }
      ]
    }
  },
  {
    $unwind: "$classes"
  },
  {
    $unwind: "$factions"
  },
  {
    $project: {
      "classes._id": 0,
      "factions._id": 0
    }
  }
])

Выход

[
  {
    "classes": {
      "classes": [
        {
          "class": "Warrior",
          "total": 1
        },
        {
          "class": "Rogue",
          "total": 1
        }
      ],
      "total": 2
    },
    "factions": {
      "factions": [
        {
          "faction": "Alliance",
          "total": 1
        },
        {
          "faction": "Horde",
          "total": 1
        }
      ],
      "total": 2
    }
  }
]
...