按文档中的键汇总总计

时间:2017-06-15 15:05:15

标签: javascript mongodb mapreduce aggregation-framework

我有一个mapreduce函数,我想在mongoDB中编写,以计算一个角色的播放次数。我的json的相关部分看起来像这样:

"playerInfo": {
"Player 1": {
  "info":{
          "characterId":17
         }
       },
"Player 2": {
      "info":{
              "characterId":20
             }
       }
}

我想计算每个“characterId”在我的文档中持续多少次,有10个玩家,从玩家1到玩家10。

两个问题:
1。当我有一个数字作为我的密钥的一部分时,如何在mongo中使用mapreduce。
2。如何在mapreduce中连接字符串,以便显示较低的代码可以正确?

db.LoL.mapReduce( function() 
                    {
                        for (var i in this.playerInfo)
                        {
                            emit(this.playerInfo.'Player '+(i).info.characterId, 1);
                        }

                    },
                  function(keys, values) {
                    return Array.sum(values)
                  }, {out: { merge: "map_reduce_example5" } } )

非常感谢您的回答!

1 个答案:

答案 0 :(得分:0)

所以这里的结构确实存在一些问题,你真的“应该”改变它

mapReduce非常简单,因为您可以通过Object.keys()

重复密钥名称
db.LoL.mapReduce(
  function() {
    Object.keys(this.playerInfo).forEach(function(key) {
      emit({ "player": key, "characterId": this.playerInfo[key].info.characterId },  1)
    })
  },
  function(values) { return Array.sum(values) },
  { 
    "query": { "playerInfo": { "$exists": true } }
    "out": { "inline": 1 }
  }
)

如果您更改数据格式以使用数组,而使用值而不是命名键的属性:

{
  "playerInfo": [
    { "player": "Player 1", "characterId": 17 },
    { "player": "Player 2", "characterId": 20 }
  ]
}

然后.aggregate()方法处理它的速度要快得多,并为大型结果集返回一个游标:

db.collection.aggregate([
  { "$unwind": "$playerInfo" },
  { "$group": {
    "_id": "$playerInfo",
    "count": { "$sum": 1 }
  }}
])

使用MongoDB 3.4及更高版本,您甚至可以使用现有结构

db.LoL.aggregate([
  { "$project": {
    "playerInfo": { "$objectToArray": "$playerInfo" }
  }},
  { "$unwind": "$playerInfo" },
  { "$group": {
     "_id": {
       "player": "$playerInfo.k", 
       "characterId": "$playerInfo.v.info.characterId"
     },
     "count": { "$sum": 1 }
  }}
])

这与mapReduce基本相同,由于使用本机运算符而不是JavaScript评估,运行速度要慢得多。