Есть ли способ вызвать пользовательскую функцию с запросом агрегации в MongoDB - PullRequest
0 голосов
/ 11 февраля 2020

У меня есть ниже структура документа:

{
   Id: 1,
   StartDate: <any date>,
   EndDate: <any date>,
   TotalValue: <any double value>
}

Я хочу один массив в выводе, который содержит каждую дату между StartDate и EndDate со значением, которое TotalValue делится на разницу дней StartDate, EndDate.

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

{
   Id: 1,
   StartDate: <any date>,
   EndDate: <any date>,
   Allocations: [{date: date1, val: TotalValue/number of Days}, {date: date2, val: TotalValue/number of Days},,,,{date: daten, val: TotalValue/number of Days}]
}


[Обновлено 17 февраля]

Теперь необходимо go шаг глубже, чем это. Предположим, у меня есть ситуация, когда для нескольких объектов в массиве root объектов я мог бы также получить массив размещения, но не по дням. Я бы получил этот диапазон мудрым. Таким образом, массив может выглядеть так:

{
   Id: 1,
   StartDate: ISODate("2019-01-01"),
   EndDate: ISODate("2019-12-31"),
   TotalValue: 3500,
   Allocations: [{startDate: ISODate("2019-01-01"), endDate: ISODate("2019-07-30"), val: 2000}, {startDate: ISODate("2019-07-01"), endDate: ISODate("2019-12-31"), val: 1500}]
},
{
   Id: 1,
   StartDate: ISODate("2020-01-01"),
   EndDate: ISODate("2020-12-31"),
   TotalValue: 5000
}

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

1 Ответ

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

Эта агрегация дает желаемый результат Allocations. Использование следующего примера входного документа :

{
   _id : ObjectId("5e42154155533a54ed5fb852"),
   Id: 1,
   StartDate: ISODate("2020-01-30"),
   EndDate: ISODate("2020-02-05"),
   TotalValue: 100
}

Запрос:

db.collection.aggregate( [
  { 
      $addFields: { 
          daysArr: { 
              $range: [ 0, { $add: [ { $divide: [ { $subtract: [ "$EndDate", "$StartDate" ] }, 86400000 ] } , 1 ] } ] 
          } 
      } 
  },
  { 
      $addFields: { 
          Allocations: { 
              $map: {
                  input: "$daysArr",
                  in: { 
                      date: { $add: [ "$StartDate", { $multiply: [ 86400000, "$$this" ] } ] },
                      val: { $divide: [ "$TotalValue", { $add: [ { $divide: [ { $subtract: [ "$EndDate", "$StartDate" ] }, 86400000 ] }, 1 ] } ] }
                   }
               }
          }
      } 
  },
  { 
      $project: { daysArr: 0 } 
  }
] )

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

{
        "_id" : ObjectId("5e42154155533a54ed5fb852"),
        "Id" : 1,
        "StartDate" : ISODate("2020-01-30T00:00:00Z"),
        "EndDate" : ISODate("2020-02-05T00:00:00Z"),
        "TotalValue" : 100,
        "Allocations" : [
            {
                    "date" : ISODate("2020-01-30T00:00:00Z"),
                    "val" : 14.285714285714286
            },
            {
                    "date" : ISODate("2020-01-31T00:00:00Z"),
                    "val" : 14.285714285714286
            },
            {
                    "date" : ISODate("2020-02-01T00:00:00Z"),
                    "val" : 14.285714285714286
            },
            {
                    "date" : ISODate("2020-02-02T00:00:00Z"),
                    "val" : 14.285714285714286
            },
            {
                    "date" : ISODate("2020-02-03T00:00:00Z"),
                    "val" : 14.285714285714286
            },
            {
                    "date" : ISODate("2020-02-04T00:00:00Z"),
                    "val" : 14.285714285714286
            },
            {
                    "date" : ISODate("2020-02-05T00:00:00Z"),
                    "val" : 14.285714285714286
            }
    ]
}



[Обновлено в соответствии с дополнением от 17 февраля]

Это объединение будет обрабатывать два типа входных документов:

{
        "_id" : ObjectId("5e4a16e96d13751bfb64572d"),
        "Id" : 1,
        "StartDate" : ISODate("2019-01-01T00:00:00Z"),
        "EndDate" : ISODate("2019-12-12T00:00:00Z"),
        "TotalValue" : 3500,
        "Allocations" : [
                {
                        "startDate" : ISODate("2019-01-01T00:00:00Z"),
                        "endDate" : ISODate("2019-01-10T00:00:00Z"),
                        "val" : 2000
                },
                {
                        "startDate" : ISODate("2019-01-11T00:00:00Z"),
                        "endDate" : ISODate("2019-01-12T00:00:00Z"),
                        "val" : 1500
                }
        ]
}
{
        "_id" : ObjectId("5e42154155533a54ed5fb852"),
        "Id" : 11,
        "StartDate" : ISODate("2020-02-01T00:00:00Z"),
        "EndDate" : ISODate("2020-02-05T00:00:00Z"),
        "TotalValue" : 100
}

Запрос агрегации:

db.collection.aggregate( [
  { 
      $addFields: { 
          Allocations: { 
              $ifNull: [ 
                  "$Allocations", 
                  [ { startDate: "$StartDate", endDate: "$EndDate", val: "$TotalValue" } ] 
              ] 
          }
      }
  },
  { 
      $addFields: { 
          Allocations: {
              $map: {
                  input: "$Allocations", 
                  in: {
                      $mergeObjects: [ 
                          "$$this", 
                          { range: { 
                                 $range: [ 
                                     0, 
                                    { $add: [ { $divide: [ { $subtract: [ "$$this.endDate", "$$this.startDate" ] }, 86400000 ] } , 1 ] } 
                                 ] 
                          } }
                      ]
                  }
              } 
          } 
      }
  },
  { 
      $unwind: "$Allocations" 
  },
  { 
      $addFields: { 
          Allocations: { 
              $map: {
                  input: "$Allocations.range",
                  in: { 
                      date: { $add: [ "$Allocations.startDate", { $multiply: [ 86400000, "$$this" ] } ] },
                      val: { $divide: [ "$Allocations.val", { $size: "$Allocations.range" } ] }
                   }
               }
          }
      } 
  },
  { 
      $group: { 
          _id: "$_id", 
          Allocations: { $push: "$Allocations" }, 
          doc: { $first: "$$ROOT" } 
    } 
  },
  { 
      $addFields: {
          "doc.Allocations": { 
              $reduce: { 
                  input: "$Allocations", initialValue: [ ],
                  in: { $concatArrays : ["$$value", "$$this"] }
              } 
          } 
      } 
  },
  { 
      $replaceRoot: { newRoot: "$doc" } 
  }
] )
...