MongoDB汇总为所有前几周的每周总和

我在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;
});

这是关于这是否需要在服务器或客户端上发生的最重要的问题.但由于聚合pipline没有这样的“全局”,所以你可能不应该在没有输出到另一个集合的情况下进行任何进一步的处理.

点赞