我在mongo中有一个棘手的数据聚合,我不知道如何直接在mongo中实现它,而不需要以后的数据处理。
以下是我馆藏文件的简化示例
[
{
"from" : ISODate("2017-01-15T00:00:00.000Z"),
"to" : ISODate("2017-02-15T00:00:00.000Z"),
"value" : 1000
},
{
"from" : ISODate("2017-02-01T00:00:00.000Z"),
"to" : ISODate("2017-02-28T00:00:00.000Z"),
"value" : 2000
},
{
"from" : ISODate("2017-02-20T00:00:00.000Z"),
"to" : ISODate("2017-03-14T00:00:00.000Z"),
"value" : 1000
}
]
不,我想获得属于特定月份的每月价值总和。
[
{janurary: 500}, /* 1/2 of interval id 1 is January so take half the value */
{february: 2833}, /* 500 + 2000 + 333 */
{march: 666}, /* 2/3 of interval id 3 is March */
]
计算必须精确,所以我不能简单地说所有月份都有30天。但我能做的是从间隔的每个月的代码中提供此信息。因此,应该可以提供此查询信息january2017 = 31 days, february2017 = 28 days, march2017 = 31 days
我知道我可以在我的node.js代码中执行此操作,但该DB中可能有很多文档,所以我宁愿不将所有这些文件提取到服务器来执行计算。
答案 0 :(得分:0)
Pah,我希望其他人提出更好的答案,但这是实现目标的一种方式:
db.collection.aggregate({
$addFields: {
dayFrom: { $dayOfMonth: "$from" },
dayTo: { $dayOfMonth: "$to" },
monthFrom: { $month: "$from" },
monthTo: { $month: "$to" },
numberOfDays: { $subtract: [ { $dayOfMonth: "$to" }, { $dayOfMonth: "$from" } ] },
numberOfMonths: { $subtract: [ { $month: "$to" }, { $month: "$from" } ] },
}
}, {
$addFields: {
numberOfDaysInFromMonth: { $dayOfMonth: { $subtract: [ { $dateFromParts : { year: { $year: "$from" }, month: { $add: [ "$monthFrom", 1 ] }, day: 1 } }, 1 ] } },
}
}, {
$addFields: {
numberOfDaysAccountingForFromMonth: { $subtract: [ { $add: [ "$numberOfDaysInFromMonth", 1 ] }, "$dayFrom" ] },
numberOfDaysAccountingForToMonth: { $subtract: [ "$dayTo", 1 ] }, // assuming the "to" day does not count anymore
}
}, {
$addFields: {
totalNumberOfDays: { $add: [ "$numberOfDaysAccountingForFromMonth", "$numberOfDaysAccountingForToMonth" ] }
}
}, {
$addFields: {
percentageAccountingForFromMonth: { $divide: [ "$numberOfDaysAccountingForFromMonth", "$totalNumberOfDays" ] },
percentageAccountingForToMonth: { $divide: [ "$numberOfDaysAccountingForToMonth", "$totalNumberOfDays" ] },
}
}, {
$facet: {
"from": [{
$group: {
_id: "$monthFrom",
sum: { $sum: { $multiply: [ "$value", "$percentageAccountingForFromMonth" ] } }
}
}],
"to": [{
$group: {
_id: "$monthTo",
sum: { $sum: { $multiply: [ "$value", "$percentageAccountingForToMonth" ] } }
}
}]
}
}, {
$project: {
total: { $concatArrays: [ "$from", "$to" ] }
}
}, {
$unwind: "$total"
}, {
$group: {
_id: "$total._id",
sum: { $sum: "$total.sum" }
}
})
一些评论:
您需要优化它以匹配您的精确定义 什么构成日期范围的一部分以及如何计算天数 (“是2018-01-30到2018-01-31 一个天还是两个天?”。
您可以使用$let和美化该查询
一些筑巢。我认为使用后续的$addFields
阶段会更容易让野兽更容易理解。
该代码不支持触及两个月以上的from
和to
值(例如2018-01-01至2018-03-01)。