Вам не обязательно нужен MapReduce для выполнения такого агрегирования, если только у вас нет явного требования использовать его.
Следующее использует инфраструктуру агрегации для выполнения агрегации, которая намного быстрее, потому что она запускает скомпилированный C ++ код, в то время как код MapReduce Javascript интерпретируется.
Рассмотрим этот конвейер, который дает желаемый результат (комментарии, описывающие каждый шаг конвейера)
db.dvdrent.aggregate([
// initial filter pipeline using $match
{ '$match': {
'$expr': {
'$eq': [
{ '$size': '$film.categories' },
1
]
}
} },
// project a new field which holds the category name
{ '$addFields': {
'category': { '$arrayElemAt': [ '$film.categories', 0 ] }
} },
// initial group - group by hour and category and aggregate counts
{ '$group': {
'_id': {
'hour': {
'$hour': {
'$dateFromString': {
'dateString': '$rental_date'
}
}
},
'category': '$category.name'
},
'count': { '$sum': 1 }
} },
// second group - group documents from the previous group pipeline by the hour and create a lit of key/value documents
{ '$group': {
'_id': '$_id.hour',
'categories': {
'$push': {
'k': '$_id.category',
'v': '$count'
}
}
} },
// convert the list of categories with counts documents to a key/value object/hash
{ '$project': {
'categories': {
'$arrayToObject': '$categories'
}
}}
])