我在 MongoDB 中有一系列文档。一个示例文档是
{
createdAt: Mon Oct 12 2015 09:45:20 GMT-0700 (PDT),
year: 2015,
week: 41
}
想象一下,这些事件跨越一年中的所有几周,而且同一周内可能会有很多次事件。我想以这样一种方式汇总它们,即结果值是每周的总和以及之前所有周的总文档数。
所以如果一年的第一周有 10 个,第二周有 20 个,结果可能是这样的
[{ week: 1, total: 10, weekTotal: 10},
{ week: 2, total: 30, weekTotal: 20}]
创建一个聚合来查找 weekTotal 非常简单。包括显示第一部分的投影
db.collection.aggregate([
{
$project: {
"createdAt": 1,
year: {$year: "$createdAt"},
week: {$week: "$createdAt"},
_id: 0
}
},
{
$group: {
_id: {year: "$year", week: "$week"},
weekTotal : { $sum : 1 }
}
},
]);
但事实证明,要根据这一周和之前的那几周来计算总和是很棘手的。
最佳答案
聚合框架无法做到这一点,因为所有操作一次只能有效地查看一个文档或分组边界。为了在“服务器”上执行此操作,您需要一些可以访问全局变量的东西来保持“运行总计”,这意味着 mapReduce
代替:
db.collection.mapReduce(
function() {
Date.prototype.getWeekNumber = function(){
var d = new Date(+this);
d.setHours(0,0,0);
d.setDate(d.getDate()+4-(d.getDay()||7));
return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7);
};
emit({ year: this.createdAt.getFullYear(), week: this.createdAt.getWeekNumber() }, 1);
},
function(values) {
return Array.sum(values);
},
{
out: { inline: 1 },
scope: { total: 0 },
finalize: function(value) {
total += value;
return { total: total, weekTotal: value }
}
}
)
如果您可以接受发生在“客户端”上的操作,那么您需要遍历聚合结果并类似地求和:
var total = 0;
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$createdAt" },
"week": { "$week": "$createdAt" }
},
"weekTotal": { "$sum": 1 }
}},
{ "$sort": { "_id": 1 } }
]).map(function(doc) {
total += doc.weekTotal;
doc.total = total;
return doc;
});
这完全取决于这是否需要在服务器或客户端上发生对您来说最有意义。但是由于聚合管道没有这样的“全局变量”,因此您可能不应该在不输出到另一个集合的情况下查看它以进行任何进一步处理。
关于MongoDB 汇总所有前几周的每周总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33577908/