как суммировать значения в соответствии со значением предыдущего документа и значением следующего документа в агрегате mongodb? - PullRequest
0 голосов
/ 11 апреля 2020

Я борюсь с некоторыми функциями агрегации в mongodb.

Скажем, у меня есть несколько подобных документов в двух коллекциях:

коллекция A:

{index: "1", time: 10:30:00, value: 12}
{index: "2", time: 10:30:20, value: 11}
{index: "1", time: 10:30:32, value: 15}
{index: "2", time: 10:31:05, value: 13}
{index: "1", time: 10:31:40, value: 14}
{index: "2", time: 10:31:43, value: 10}

коллекция B:

{index: "1", time: 10:30:10, cost: 10}
{index: "2", time: 10:30:15, cost: 12}
{index: "1", time: 10:30:30, cost: 8}
{index: "2", time: 10:30:50, cost: 9}
{index: "1", time: 10:31:10, cost: 10}
{index: "2", time: 10:31:23, cost: 11}

И я хочу вернуть это:

{index: "1", value: 12, totalCost: 18}
{index: "1", value: 15, totalCost: 10}
{index: "1", value: 14, totalCost: 0}
{index: "2", value: 11, totalCost: 9}
{index: "2", value: 13, totalCost: 9}
{index: "2", value: 10, totalCost: 11}

{index: "1", value: 12, totalCost: 18} результата, означающего, что:

В соответствии с документами коллекции A 'тот индекс = " 1 "и время между 10:30:00 и 10:30:32, запрашивая документы коллекции B с индексом" 1 "и временем между 10:30:00 и 10:30:32, а затем суммируют его стоимость как totalCost.

Может ли агрегат mongodb реализовать? Спасибо!

1 Ответ

0 голосов
/ 11 апреля 2020

Ну, нам нужно использовать несколько операторов.

Кстати: Пожалуйста, предоставьте правильное ожидание, так как ваш результат, основанный на данных выборки, неверен

{index: "1", value: 12, totalCost: 18} -> OK
{index: "1", value: 14, totalCost: 0}  -> OK
{index: "1", value: 15, totalCost: 10} -> OK
{index: "2", value: 10, totalCost: 11} -> KO (No B document greater than 10:31:43)
{index: "2", value: 11, totalCost: 9}  -> OK
{index: "2", value: 13, totalCost: 9}  -> KO (For 10:31:05 - 10:31:43, matchs only {index: "2", time: 10:31:23, cost: 11})

Конвейер объяснение

  1. $ graphLookup используется для построения иерархии для данного index значения.
  2. Нам необходимо удалить из иерархии:
    • узел с тем же _id, что и у родителя
    • все дети ниже, чем у родителя time
    • , ближе всего time к значению time родителя
  3. Мы присоединяемся к коллекции B и принимаем предметы:
    • То же index, что и A документы
    • B's time между родителем A time и дочерью A time
  4. Преобразуем в желаемый результат и суммируем totalCost

db.A.aggregate([
  {
    $graphLookup: {
      from: "A",
      startWith: "$index",
      connectFromField: "index",
      connectToField: "index",
      as: "range"
    }
  },
  {
    $addFields: {
      range: {
        $reduce: {
          input: "$range",
          initialValue: {
            index: "$index",
            time: "23:59:59",
            value: 0
          },
          in: {
            $cond: [
              {
                $and: [
                  {
                    $ne: [ "$_id", "$$this._id" ]
                  },
                  {
                    $gt: [ "$$this.time", "$time" ]
                  },
                  {
                    $lt: [ "$$this.time", "$$value.time" ]
                  }
                ]
              },
              "$$this",
              "$$value"
            ]
          }
        }
      }
    }
  },
  {
    $lookup: {
      from: "B",
      let: {
        index: "$index",
        start: "$time",
        end: "$range.time"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                {
                  $eq: [ "$$index", "$index" ]
                },
                {
                  $and: [
                    {
                      $gt: [ "$time", "$$start" ]
                    },
                    {
                      $lt: [ "$time", "$$end" ]
                    }
                  ]
                }
              ]
            }
          }
        }
      ],
      as: "linked"
    }
  },
  {
    $project: {
      _id: 0,
      index: 1,
      value: 1,
      totalCost: { $sum: "$linked.cost" }
    }
  },
  {
    $sort: {
      index: 1,
      value: 1
    }
  }
])

MongoPlayground

...