【问题标题】:MongoDB Aggregate for a sum on a per week basis for all prior weeksMongoDB 以每周为基础汇总前几周的总和
【发布时间】:2016-02-08 06:08:59
【问题描述】:

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

但要根据那一周和之前的那几周来计算总和是很棘手的。

【问题讨论】:

    标签: mongodb mapreduce mongodb-query aggregation-framework


    【解决方案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;
    });
    

    这完全取决于是否需要在服务器或客户端上发生这对您来说最有意义。但是由于聚合管道没有这样的“全局变量”,那么您可能不应该在不输出到另一个集合的情况下查看它以进行任何进一步的处理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-13
      • 2018-06-02
      • 2022-06-27
      • 1970-01-01
      • 2023-01-16
      相关资源
      最近更新 更多