Как использовать одну коллекцию для сопоставления другой коллекции в MongoDB - PullRequest
0 голосов
/ 18 января 2020

У меня есть набор данных, подобный следующему

[{id:1,month:1,count:1},{id:1,month:2,count:2},{id:1,month:3,count:3}......,
{id:2,month:1,count:1},{id:2,month:2,count:2},{id:2,month:3,count:3}.......,
........
........
{id:19,month:1,count:1},{id:19,month:2,count:2},{id:19,month:3,count:3}.......,]

, и таблица выглядит следующим образом.

|id|month|count|
|1 |  1  | 1   | 
.............
.........
|19| 12  | 4   |

есть еще один id как divisonId, и он отображается на идентификаторы выше, как показано ниже

{1:[1,2,4,5],2:[3,6,8,9],3:[7,10,....19]}

, и таблица сопоставления выглядит следующим образом.

|divisionId| id|
|    1     | 1 |
|    1     | 2 |
|    1     | 4 |
|    1     | 5 |
|    2     | 3 |
|    2     | 6 |
......
......

, поэтому теперь мне нужно объединить данные, суммировать и перегруппировать их в соответствии с divisonIds.

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

[{divsionId:1,month:1,count:19},{divisionId:1,month:2,count:53},{divisionId:1,month:3,count:66}......,
    {divisionId:2,month:1,count:21},{divisionId:2,month:2,count:82},{divisionId:2,month:3,count:63}.......,   
    {divisionId:3,month:1,count:1},{divisionId:3,month:2,count:2},{divisionId:3,month:3,count:3}.......,]

, а таблица должна выглядеть следующим образом:

| divisionId| month | count |
|     1     |   1   |  200  |
|     1     |   2   |  400  |
|     1     |   3   |  300  |
.....
.....
|     3     |   11  |  500  |
|     3     |   12  |  600  |

, поэтому в основном она просто сопоставляет идентификаторы с DivisionId и суммируйте отдельные месяцы по этим идентификаторам и объедините новую коллекцию для возврата данных. Мне не разрешается помещать DivisionId в исходную таблицу из-за того, что идентификаторы могут быть назначены для различных дивидендов в будущем, или было бы намного проще просто использовать агрегатные методы.

В настоящее время один из способов сделать это - использовать Javascript, чтобы получить данные для идентификаторов отдельно в соответствии с отображением, затем выполнить расчет и набрать sh до Монго, чтобы сохранить его как новый. коллекции, поэтому, когда пользовательский интерфейс запрашивает данные в будущем, он просто читает запрос, сохраняя дорогостоящий расчет. Но было бы замечательно, если бы я мог решить эту проблему, просто используя некоторый продвинутый синтаксис mongodb. Пожалуйста, дайте мне знать, если у вас есть какие-то хитрости, которые я мог бы использовать. Спасибо.

Ответы [ 2 ]

0 голосов
/ 18 января 2020

ASSUMPTION

Коллекция months имеет следующую структуру: {id:1,month:1,count:1}

Коллекция divisions имеет следующую структуру: {1:[1,2,4,5],2:[3,6,8,9],3:[7,10,19]}

Вы можете выполнить такой запрос:

db.divisons.aggregate([
  {
    $addFields: {
      data: {
        $filter: {
          input: {
            $objectToArray: "$$ROOT"
          },
          cond: {
            $isArray: "$$this.v"
          }
        }
      }
    }
  },
  {
    $unwind: "$data"
  },
  {
    $lookup: {
      from: "months",
      let: {
        ids: "$data.v"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $in: [
                "$id",
                "$$ids"
              ]
            }
          }
        }
      ],
      as: "months"
    }
  },
  {
    $unwind: "$months"
  },
  {
    $group: {
      _id: {
        divisionId: "$data.k",
        month: "$months.month"
      },
      count: {
        $sum: "$months.count"
      }
    }
  },
  {
    $project: {
      _id: 0,
      divisionId: "$_id.divisionId",
      month: "$_id.month",
      count: "$count"
    }
  },
  {
    $sort: {
      divisionId: 1,
      month: 1
    }
  }
])

MongoPlayground

ОБЪЯСНЕНИЕ

Ваша коллекция divisions не нормализовала key:value пар, поэтому наш первый шаг - преобразование 1:[...], 2:[...] соединяются в [{k:"1", v:[...]}, {k:2, v:[...]}] пары с оператором $objectToArray.

Затем мы выравниваем массив предыдущего шага с помощью $unwind и применяем $lookup с некоррелированными подзапросами для пересечения с months коллекцией.

Последние шаги, мы $group на divisionId + month и суммой count значения.

Чтобы сохранить результат в другой коллекции, вам нужно используйте оператор $ out или $ merge .

0 голосов
/ 18 января 2020

Пожалуйста, попробуйте это:

db.divisionIdCollName.aggregate([{
    $lookup:
    {
        from: "idCollectionName",
        let: { ids: "$id" },
        pipeline: [
            {
                $match:
                {
                    $expr:
                        { $in: ["$id", "$$ids"] }
                }
            }
        ],
        as: "data"
    }
}, { $unwind: { path: "$data", preserveNullAndEmptyArrays: true } },
{ $group: { _id: { divisionId: '$divisionId', month: '$data.month' }, month: { $first: '$data.month' }, count: { $sum: '$data.count' } } },
{$addFields : {divisionId : '$_id.divisionId'}}, {$project : {_id:0}}
])

Результат: Пн go детская площадка

Вы можете проверить результаты там - как только вы если агрегация возвращает правильные результаты, попробуйте добавить этап $ merge , чтобы записать результат в другую коллекцию, вы можете использовать $ out вместо $merge, но мы используем $merge is потому что если данное имя совпадает с любым именем коллекции в базе данных $out будет заменять всю коллекцию результатом агрегации каждый раз, когда выполняется запрос, который является разрушительным и не должен использоваться, если этот запрос должен обновить существующие записи в коллекции, поэтому мы Вы используете $merge, пожалуйста, прочитайте о тех двух, прежде чем использовать, поэтому добавьте ниже этап как последний этап после $project

Примечание: $merge является новым в v 4.2, $out> = v 2.6. Если вы делаете $merge, так как вы указываете два поля on: [ "divisionId", "month" ] - поэтому в коллекции должен быть создан уникальный составной индекс divisionIdCollNameNew - Так что да, нам нужно вручную создать коллекцию и создать уникальный индекс, а затем выполнить запрос.

Создать коллекцию и индекс:

db.createCollection("divisionIdCollNameNew")     
db.divisionIdCollNameNew.createIndex ( { divisionId: 1, month: 1 }, { unique: true } )

Конечный этап:

 { $merge : { into: { coll: "divisionIdCollNameNew" }, on: [ "divisionId", "month" ], whenNotMatched: "insert" } }
...