有没有一种方法可以在MongoDB中使用聚合查询调用自定义函数

时间:2020-02-11 01:26:26

标签: mongodb aggregation-framework

我具有以下文档结构:

{
   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}]
}


[更新于2月17日]

现在,需要比这更进一步。假设我遇到这样的情况,对于根对象数组中的几个对象,我也可能获得分配数组,但不是按日分配。我会明智地做到这一点。所以数组可能看起来像这样:

{
   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 :(得分:0)

此聚合可提供所需的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
            }
    ]
}



[根据2月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" } 
  }
] )