Сводные итоги по ключам в документе

1

У меня есть функция mapreduce, которую я хочу написать в mongoDB, чтобы подсчитать, сколько раз был воспроизведен персонаж. Соответствующая часть моего json выглядит так:

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

Я хочу подсчитать, сколько раз каждый "characterId" сохраняется в моих документах, есть 10 игроков, от игрока 1 до игрока 10.

Два вопроса:
1. Как использовать mapreduce в mongo, когда у меня есть номер в составе моего ключа.
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" } } )

Большое спасибо за ваши ответы!

Теги:
aggregation-framework
mapreduce

1 ответ

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, которая работает намного медленнее.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню