组结果mongoDB

时间:2015-02-09 10:38:38

标签: mongodb mapreduce mongodb-query aggregation-framework

我有一个像这样的数组国家/地区的集合。我想总结各国的价值观。

{
  "_id": ObjectId("54cd5e7804f3b06c3c247428"),
  "country_json": {
     "AE": NumberLong("13"),
     "RU": NumberLong("16"),
     "BA": NumberLong("10"),
     ...
  }
},
{
   "_id": ObjectId("54cd5e7804f3b06c3c247429"),
   "country_json": {
      "RU": NumberLong("12"),
      "ES": NumberLong("28"),
      "DE": NumberLong("16"),
      "AU": NumberLong("44"),
      ...
    } 
 }

如何汇总各国的价值以获得这样的结果?

{
   "AE": 13,
   "RU": 28,
   ..  
}

2 个答案:

答案 0 :(得分:2)

这可以使用aggregation

完成
> db.test.aggregate([
    {$project: { 
        RU: "$country_json.RU", 
        AE: "$country_json.AE", 
        BA: "$country_json.BA"
    }}, 
    {$group: {
       _id: null, 
       RU: {$sum: "$RU"}, 
       AE: {$sum: "$AE"}, 
       BA: {$sum: "$BA"}
    }
])

输出:

{
    "_id" : null, 
    "RU" : NumberLong(28), 
    "AE" : NumberLong(13), 
    "BA" : NumberLong(10) 
}

答案 1 :(得分:1)

如果您打算在"键"之间汇总统计数据,那么这不是一个非常好的文档结构。像这样。并非真正喜欢"数据作为关键名称"无论如何,但重点是它没有“好好发挥”#34;由于各地的密钥名称不同,因此有许多MongoDB查询表单。

特别是对于聚合框架,存储数据的更好形式是在实际数组中,如下所示:

{
    "_id": ObjectId("54cd5e7804f3b06c3c247428"),
    "countries": [
       { "key": "AE", "value": NumberLong("13"),
       { "key": "RU", "value": NumberLong("16"),
       { "key": "BA", "value": NumberLong("10")
    ]
}

通过它,您可以简单地使用聚合操作:

db.collection.aggregate([
    { "$unwind": "$countries" },
    { "$group": {
        "_id": "$countries.key",
        "value": { "$sum": "$countries.value" }
    }}
])

这会给你带来如下结果:

{ "_id": "AE", "value": NumberLong(13) },
{ "_id": "RU", "value": NumberLong(28) }

这种结构确实发挥得很好并且#34;使用聚合框架和其他MongoDB查询模式,因为它实际上是它的预期和#34;要以这种方式使用数据时要完成。

在不更改文档结构的情况下,您必须使用JavaScript评估方法来遍历文档的键,因为这是使用MongoDB执行此操作的唯一方法:

db.collection.mapReduce(
    function() {
        var country = this.country_json;
        Object.keys(country).forEach(function(key) {
            emit( key, country[key] );
        });
    },
    function(key,values) {
        return values.reduce(function(p,v) { return NumberLong(p+v) });
    },
    { "out": { "inline": 1 } }
)

这将产生与聚合示例输出中显示的完全相同的结果,但是使用当前文档结构。当然,JavaScript评估的使用效率不如聚合框架使用的本机方法那么高,因此它不会表现得那么好。

还要注意这里可能遇到的问题"大值"在您的转换NumberLong字段中,因为它们以JavaScipt的方式表示的主要原因是JavaScipt本身对该值的大小有限制,而不是可以表示的。可能你的价值观是微不足道的,但只是简单地“#34; cast"那样,但是根据意图,对于足够大的数字,那么数学就会失败。

因此,考虑更改构建此数据的方式以简化操作通常是个好主意。最后要注意的是,您对单个文档中所有键所期望的输出类似于反直觉,因为它还需要遍历"散列/映射"而不是使用数组或游标的自然迭代器。