MondoDB Aggregate - 每天的绝对计数

时间:2016-01-21 15:23:09

标签: mongodb mapreduce aggregation-framework

我有以下(已经汇总的)集合

{ "_id" : { "day" : "2015-02-01" }, "total" : 2 }
{ "_id" : { "day" : "2015-02-02" }, "total" : 3 }
{ "_id" : { "day" : "2015-02-03" }, "total" : 10 }
{ "_id" : { "day" : "2015-02-04" }, "total" : 10 }
{ "_id" : { "day" : "2015-02-05" }, "total" : 5 }

我需要的是计算每一天的绝对值,总结前几天。所以预期的结果将是上面的情况

{ "_id" : { "day" : "2015-02-01" }, "absolutetotalforday" : 2 }
{ "_id" : { "day" : "2015-02-02" }, "absolutetotalforday" : 5 }
{ "_id" : { "day" : "2015-02-03" }, "absolutetotalforday" : 15 }
{ "_id" : { "day" : "2015-02-04" }, "absolutetotalforday" : 25 }
{ "_id" : { "day" : "2015-02-05" }, "absolutetotalforday" : 30 }

目前还不知道如何通过1个查询实现此目的。当然,我可以为我感兴趣的每一天做一笔钱,但这可能是一个很长的时间范围

任何帮助表示赞赏

1 个答案:

答案 0 :(得分:0)

因为聚合框架没有机制知道先前文档的价值,或者之前的#34;分组"在这种情况下,您最好的选择是使用 Map-Reduce

Map-Reduce 会为您提供"运行总计"对于您需要的当前总数,虽然这不会在所需的密钥absolutetotalforday中,而是在名为value的密钥中,因为减少的值始终位于value键。

以下 mapReduce() 操作会为您提供所需的结果,假设前一个聚合操作的结果输出到名为agg_results的单独集合中:

db.agg_results.mapReduce(
    function() { emit( this._id, this.total ); },  
    function(key, values) { return Array.sum(values); },
    { 
        "scope": { "total": 0 },
        "finalize": function(key, value) {
            total += value;
            return total;
        },
        "out": { "inline": 1 }
    }
); 

示例输出

{
    "results" : [ 
        {
            "_id" : {
                "day" : "2015-02-01"
            },
            "value" : 2
        }, 
        {
            "_id" : {
                "day" : "2015-02-02"
            },
            "value" : 5
        }, 
        {
            "_id" : {
                "day" : "2015-02-03"
            },
            "value" : 15
        }, 
        {
            "_id" : {
                "day" : "2015-02-04"
            },
            "value" : 25
        }, 
        {
            "_id" : {
                "day" : "2015-02-05"
            },
            "value" : 30
        }
    ],
    "timeMillis" : 0,
    "counts" : {
        "input" : 5,
        "emit" : 5,
        "reduce" : 0,
        "output" : 5
    },
    "ok" : 1
}

对结果进行排序不适用于内联结果和String类型的日期。相反,尝试将日期字符串转换为JavaScript日期对象,将结果写入集合,然后对该集合运行排序:

db.agg_results.mapReduce(
    function() { emit( new Date(this._id.day), this.total ); },  
    function(key, values) { return Array.sum(values); },
    { 
        "scope": { "total": 0 },
        "finalize": function(key, value) {
            total += value;
            return total;
        },
        "out": "tmpResults"
    }
); 

示例输出(带排序)

> db.tmpResults.find().sort({_id: 1})
{ "_id" : ISODate("2015-02-01T00:00:00Z"), "value" : 2 }
{ "_id" : ISODate("2015-02-02T00:00:00Z"), "value" : 5 }
{ "_id" : ISODate("2015-02-03T00:00:00Z"), "value" : 15 }
{ "_id" : ISODate("2015-02-04T00:00:00Z"), "value" : 25 }
{ "_id" : ISODate("2015-02-05T00:00:00Z"), "value" : 30 }
>