Расчетный запрос MongoDB - кумулятивное умножение

Недавно я начал работать в Mongodb для POC. У меня есть одна коллекция json ниже

db.ccpsample.insertMany([
  {
    "ccp_id":1,
    "period":601,
    "sales":100.00
  },
  {
    "ccp_id":1,
    "period":602,
    "growth":2.0,
    "sales":"NULL"    ##sales=100.00*(1+(2.0/100)) -- 100.00 comes from(ccp_id:1 and period=601) 
  },
  {
    "ccp_id":1,
    "period":603,
    "growth":3.0,
    "sales":"NULL"   ##sales=100.00*(1+(2.0/100))**(1+(3.0/100))-- 100.00 comes from(ccp_id:1 and period=601) 2.0 comes from (ccp_id:2 and period=602)  
  },
  {
    "ccp_id":2,
    "period":601,
    "sales":200.00
  },
  {
    "ccp_id":2,
    "period":602,
    "growth":2.0,
    "sales":"NULL"   ##sales=200.00*(1+(2.0/100))
  },
  {
    "ccp_id":2,
    "period":603,
    "growth":3.0,
    "sales":"NULL"   ##same like above
  }
])

И мне нужно рассчитать поле продаж, которое имеет значение NULL, используя вышеуказанные документы с условиями соответствия ccp_id, которые должны быть одинаковыми, а поле периода должно быть равно 601. Я добавил строку, чтобы продемонстрировать расчет поля продаж в самой коллекции выше. Я пробовал с $graphlookup, но безуспешно. Можете ли вы, люди, любезно помочь или предложить какой-то способ?


person Tharunkumar Reddy    schedule 22.03.2018    source источник
comment
Можете ли вы предоставить формулу sales? Потому что эти примеры мало помогают.   -  person willie17    schedule 01.04.2018


Ответы (1)


Вы можете использовать следующую агрегацию:

db.ccpsample.aggregate([
  { $sort: { ccp_id: 1, period: 1 } },
  { 
    $group: {
      _id: "$ccp_id",
      items: { $push: "$$ROOT" },
      baseSale: { $first: "$sales" },
      growths: { $push: "$growth" }
    }
  },
  {
    $unwind: {
      path: "$items",
      includeArrayIndex: "index"
    }
  },
  {
    $project: {
      cpp_id: "$items.cpp_id",
      period: "$items.period",
      growth: "$items.growth",
      sales: {
        $cond: {
          if: { $ne: [ "$items.sales", "NULL" ] },
          then: "$items.sales",
          else: {
            $reduce: {
              input: { $slice: [ "$growths", "$index" ] },
              initialValue: "$baseSale",
              in: { $multiply: [ "$$value", { $add: [1, { $divide: [ "$$this", 100 ] }] } ] }
            }
          }
        }
      }
    }
  }
])

В основном, чтобы рассчитать значение элемента n-th, вам нужно знать следующие вещи:

  • стоимость продаж первого элемента ($first в $group)
  • массив всех growths ($push в $group)
  • n указывает, сколько умножений вам нужно выполнить

Чтобы вычислить индекс, вы должны $push объединить все элементы в один массив, а затем использовать $unwind с опцией includeArrayIndex, которая будет вставлять индекс развернутого массива в поле index.

Последний шаг вычисляет кумулятивное умножение. Он использует $slice с полем index для оценки количества growths должен быть обработан. Таким образом, будет один элемент для 601, два элемента для 602 и так далее.

Затем пришло время для $reduce обработать этот массив и выполните умножение на основе вашей формулы: (1 + (growth/100))

person mickl    schedule 02.04.2018
comment
Измените спецификацию $slice на $slice: [ "$growths", 1, "$index" ], чтобы правильно сместить нарезку. В остальном хорошее решение! - person Donny Winston; 06.04.2018
comment
@DonnyWinston Я не могу этого сделать. growths - это массив из 2 элементов в обеих группах, так как нет growth для первого документа в каждой группе, поэтому нет необходимости иметь смещение - person mickl; 06.04.2018
comment
@mickl Спасибо за ответ !! И можете ли вы дать мне какие-либо предложения по усилению агрегации mongodb? - person Tharunkumar Reddy; 08.04.2018
comment
@Buddi Я считаю, что написание кода — лучший способ научиться программированию :) В этом случае у MongoDB есть действительно полезные документы. Спасибо за действительно интересный вопрос! - person mickl; 08.04.2018
comment
@mickl спасибо, ты прав! Я думал, что нулевое значение будет $pushed для документа без поля роста, но вы правы, это двухэлементный массив. Спасибо за разъяснения! - person Donny Winston; 09.04.2018