如何在MongoDB集合中汇总许多键

时间:2014-06-16 17:35:37

标签: mongodb aggregation-framework

我有一个MongoDB集合,其中的文档格式为:

{
    year: 1900,
    alabama: 145,
    arkansas: 103,
    // ... for all 50 US states
}

我想要一个查询,给出每个州的集合总和。结果可能如下:

{
    alabama: 1360492,
    arkansas: 598023,
    // ... and so on
}

我能想到的最好的是一个包含50个术语的聚合查询:

db.sample.aggregate({$group: {
    _id: "",
    alabama: {$sum: "$alabama"},
    arkansas: {$sum: "$arkansas"},
    // ... and so on
}});

有没有办法构建查询,允许我只提供需要求和的字段名数组?

1 个答案:

答案 0 :(得分:4)

我不知道使用聚合框架的方法,但使用mapreduce,它是相当直接的;

> db.test.insert({ year: 1900, alabama: 145, arkansas: 103 })

> db.test.insert({ year: 1901, alabama: 100, arkansas: 77  })

// Map function, emits the state name and the value for each entry
> var m = function () { 
                        for(var key in this) {
                          if(this.hasOwnProperty(key) && 
                             key != 'year' && key!='_id')
                            emit(key, this[key])
                        }
                      }

// Reduce function, just sums up the score per state
> var r = function (state, score) { return Array.sum(score); }

// Run mapreduce with map function m, reduce function r, and output inline
> db.test.mapReduce(m, r, {out:{inline:1}})

{
"results" : [
    {
        "_id" : "alabama",
        "value" : 245
    },
    {
        "_id" : "arkansas",
        "value" : 180
    }
]
}

编辑:为了能够使用聚合框架,我无法看到一种方法,只需稍微改变数据模型就可以作为密钥访问状态;

> db.test2.insert({ year: 1900, data:[{k:"alabama", v:145}, 
                                      {k:"arkansas", v:103}] } )

> db.test2.insert({ year: 1901, data:[{k:"alabama", v:100}, 
                                      {k:"arkansas", v:77}] } )

// Unwind data, and group it back together by key while summing the values;
> db.test2.aggregate({$unwind:"$data"},
                     {$group:{_id:"$data.k",total:{$sum: "$data.v"}}})

{ "_id" : "arkansas", "total" : 180 }
{ "_id" : "alabama", "total" : 245 }