У меня есть функция 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" } } )
Большое спасибо за ваши ответы!
Таким образом, в этой структуре действительно есть пара ошибок, и вы действительно "должны" изменить ее
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, которая работает намного медленнее.