使用MongoDB中的聚合对不同字段求和

时间:2017-04-26 20:51:57

标签: mongodb mongodb-query aggregation-framework

我在test集合中有一个文档架构,如下所示:

{
  "_id" : NumberLong("A unique number"),
  "text" : {
         "characters_map" : {
                          "a" : 4,
                          "f" : 3,
                          "b" : 6,
                            ...
                          "o" : 3
                         }
            ...
         }
    ...
}

我想计算整个集合中每个角色的总和。我尝试使用aggregation framework,但似乎我做错了。

我开始分别计算每个角色(即' a'),但没有运气。我最好的方法是:

> db.test.aggregate([
    { "$group" : {
         _id : { a_count : "$text.characters_map.a" },
         counter : { "$sum" : "$text.characters_map.a" }
      }
    }
  ])

a_count代表id的名称。

导致:

{ "_id" : { "a_map" : 8 }, "counter" : 8 }
{ "_id" : { "a_map" : 5 }, "counter" : 5 }
{ "_id" : { "a_map" : 7 }, "counter" : 21 }
 ...

不完全是假的,但不是我想要的。这些结果意味着我有1个文档,其字段为:{ "a" : 8, ... },另外1个文档包含:{ "a" : 5, ... },3个文档包含:{ "a" : 7, ... }

有没有办法将这些字段组合在一起" a"水平?我的方法完全错了吗?

1 个答案:

答案 0 :(得分:2)

您必须将结构更改为以下内容。(首选)

[{
  "text" : { "characters_map" : [{"k":"a", "v":4},  {"k":"b", "v":8},  {"k":"c", "v":5}, {"k":"d", "v":4  }]  }
}]

您可以按照在帖子中尝试的方式使用聚合。

db.test.aggregate([
 {$unwind:"$text.characters_map"},
 {$group:{_id:"$text.characters_map.k", counter:{$sum:"$text.characters_map.v"}}}
 ])

如果您无法改变结构,这就是解决方案。

您可以使用3.4.4版本并使用$objectToArray& $arrayToObject可在动态键和标签值对之间切换。

阶段1:将动态characters_map密钥转换为标签值对。

第二阶段& 3:$unwind&关于角色的$group并计算其数量。

第4阶段& 5:将最后一个分组的输出分组为键值对数组,然后$arrayToObject将键值对转换为动态键。

db.test.aggregate([
 {$addFields: {"text.characters_map": {$objectToArray: "$text.characters_map"}}},
 {$unwind:"$text.characters_map"},
 {$group:{_id:"$text.characters_map.k", counter:{$sum:"$text.characters_map.v"}}},
 {$group:{_id:null, arraykeyval:{$push:{k:"$_id", v:"$counter"}}}},
 {$project:{result: {$arrayToObject:"$arraykeyval"}}}
 ])