【问题标题】:is there a way to call custom function with Aggregation query in MongoDB有没有办法在 MongoDB 中使用聚合查询调用自定义函数
【发布时间】:2020-02-17 13:43:46
【问题描述】:

我有以下文档结构:

{
   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 均分。

【问题讨论】:

  • val: TotalValue/number of Days:因此,Allocations 数组中的所有元素的值都相同。
  • 是的,没错@prasad_
  • 那么,为什么要在数组的每个元素中使用它呢?您可以在数组之外有一个字段。
  • 这里的主要要求是生成上面的数组,我需要在管道的后期使用,例如,按日期分组。
  • 我发布了一个答案,它给出了您帖子中描述的 Allocations 数组 - 使用聚合查询

标签: mongodb aggregation-framework


【解决方案1】:

这个聚合给出了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" } 
  }
] )

【讨论】:

  • 我做的一个假设是天数(日期差异)计算为,例如,对于日期“2020-01-30”和“2020-02-05”, days 被视为 7(包括开始和结束日期)。
  • 更新了增强功能的答案。
猜你喜欢
  • 2020-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多