我具有以下文档结构:
{
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平均分配。
答案 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
}
]
}
此汇总将处理两种类型的输入文档:
{
"_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" }
}
] )