Вложенные вложенные массивы в Монго - PullRequest
2 голосов
/ 14 января 2020

В моей коллекции есть следующая схема:

{
    _id: ObjectId,
    foo: [
            {
                bar_id: ObjectId,
                bar_list: [
                    {...},
                    {...},
                ]
            },
            {
                bar_id: ObjectId,
                bar_list: [
                    {...},
                    {...},
                ]
            }
            ...
        ]
    ],
    relations: {
        relation_type: [
            {
                relation_id: ObjectId,
                ...
            }
        ]
        ...
    }
}

I wi sh, чтобы создать новый документ с аналогичной структурой (relations не требуется в новом документе), так как входные документы, но это агрегирование по relation_id и где массивы bar_list каждого входного документа объединены (включая дубликаты).

Для иллюстрации:

Документ 1

{
    _id: 1,
    foo: [
            {
                bar_id: 77,
                bar_list: [
                    {a, b},
                    {c, d},
                ]
            },
            {
                bar_id: 88,
                bar_list: [
                    {u, v},
                    {w, x},
                    {y, z},
                ]
            }
        ]
    ],
    relations: {
        relation_type: [
            {
                relation_id: 666,
                ...
            }
        ]
        ...
    }
}

Документ 2

{
    _id: 2,
    foo: [
            {
                bar_id: 77,
                bar_list: [
                    {a, b},
                    {e, f},
                    {g, h},
                ]
            },
            {
                bar_id: 88,
                bar_list: [
                    {u, v},
                ]
            }
        ]
    ],
    relations: {
        relation_type: [
            {
                relation_id: 666,
                ...
            }
        ]
        ...
    }
}

Выходной документ

{
    foo: [
            {
                bar_id: 77,
                bar_list: [
                    {a, b},
                    {c, d},
                    {a, b},
                    {e, f},
                    {g, h},
                ]
            },
            {
                bar_id: 88,
                bar_list: [
                    {u, v},
                    {w, x},
                    {y, z},
                    {u, v},
                ]
            }
        ]
    ],
}

Первая часть фильтрации совпадений с relations.relation_type.relation_id проста. Но как мне объединить массив на основе bar_id и отформатировать результат, как требуется? Вот что у меня есть:

db.getCollection('example').aggregate([
    {'$match': {'relations.relation_type.relation_id': 666}},
    // Some sore of $group, $mergeObjects or $concatArrays next?
])

Любая помощь приветствуется.

1 Ответ

1 голос
/ 14 января 2020

Объяснение

  1. При $ раскручивании мы получаем сглаживание foo.
  2. Теперь мы $ group от bar_id и Накопить массив bar_list со значениями key:pair.
  3. Мы используем оператор $ redu * для объединения в один массив bar_list массивов
  4. $ group помогает нам накапливать insde foo документы верхнего уровня.
  5. (необязательно) $ project удаляет _id поле

db.collection.aggregate([
  {
    "$match": {
      "relations.relation_type.relation_id": 666
    }
  },
  {
    $unwind: "$foo"
  },
  {
    $group: {
      _id: "$foo.bar_id",
      bar_list: {
        $push: "$foo.bar_list"
      }
    }
  },
  {
    $project: {
      _id: 0,
      bar_id: "$_id",
      bar_list: {
        $reduce: {
          input: "$bar_list",
          initialValue: [],
          in: {
            $concatArrays: [
              "$$value",
              "$$this"
            ]
          }
        }
      }
    }
  },
  {
    $group: {
      _id: null,
      foo: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $project: {
      _id: 0
    }
  }
])

MongoPlayground

...