我的数据库中有一些看起来像这样的对象:
{
"_id": ObjectId("563f8c320ef987c122aeeb4a"),
"num": 1515,
"createdAt": ISODate("2015-10-29T21:14:26.477Z"),
}
我想编写一个汇总,将所有汇总在一起的特定ID汇总起来,得出今天,本周和本月的总数,然后在一个查询中进行汇总。我为此任务编写了三个单独的查询,但是我想知道是否可以提高效率并在一个查询中完成它。
编辑
有人提到mapReduce作为解决方案。看来这是一个很有前途的解决方案,但是我无法从简单的查询中得到任何回报。以下是我尝试过的内容:
var o = {};
o.map = function () { emit( this.num, this.createdAt ) }
o.reduce = function (k, vals) { return vals }
o.query = {
_id: req.user._id
}
Submission.mapReduce(o, function (err, results) {
console.log(results)
})
控制台记录一个空数组。我也尝试过将_id
转换为猫鼬对象ID,但它仍返回一个空数组。
这实际上是一个关于您期望输出看起来如何的问题,因为任何汇总结果本质上都需要按照最低级别进行分组,然后逐步按较高的“粒度”进行分组,直到达到最高级别(“月”)为止。这种暗示最终将数据按“月”分组,除非您将其细分。
本质上,逐步地$group
:
db.collection.aggregate([
// First total per day. Rounding dates with math here
{ "$group": {
"_id": {
"$add": [
{ "$subtract": [
{ "$subtract": [ "$createdAt", new Date(0) ] },
{ "$mod": [
{ "$subtract": [ "$createdAt", new Date(0) ] },
1000 * 60 * 60 * 24
]}
]},
new Date(0)
]
},
"week": { "$first": { "$week": "$createdAt" } },
"month": { "$first": { "$month": "$createdAt" } },
"total": { "$sum": "$num" }
}},
// Then group by week
{ "$group": {
"_id": "$week",
"month": { "$first": "$month" },
"days": {
"$push": {
"day": "$_id",
"total": "$total"
}
},
"total": { "$sum": "$total" }
}},
// Then group by month
{ "$group": {
"_id": "$month",
"weeks": {
"$push": {
"week": "$_id",
"total": "$total",
"days": "$days"
}
},
"total": { "$sum": "$total" }
}}
])
因此,每天汇总的第一个级别之后的每个级别,然后由于其“舍入”值而逐渐推入数组内容,然后在该级别也汇总总数。
如果您想要一个更平坦的输出,每天有一条记录,其中包含每周和每月的总数以及一天的总数,那么只需$unwind
在管道的末尾添加两个语句即可:
{ "$unwind": "$weeks" },
{ "$unwind": "$weeks.days" }
$project
如有必要,还可以选择将“点缀”字段变得更平整和可读。
如果您要跨越“年”,那么至少要在“周”级别将这样的操作包括在分组键中,这样您就不可能合并来自不同年份的数据,并且它们是分开的。
在对日期进行四舍五入时,使用“日期数学”方法也是我自己的普遍偏爱,因为它返回一个Date
对象,但是在“天”以外的其他级别使用的方法是,您可以替代地使用日期聚合运算符。
无需这样做,mapReduce
因为这是相当直观的,并且一个月中的天数有限,这意味着在内容中嵌套数组而聚合时不会打破BSON限制。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句