###Collections Salas{_id} Reservas{_id, sala_id, data}
###Preciso contar as reservas de cada sala por uma data:
map = function () {
emit(this.sala_id, [1]);
}
reduce = function (sala, values) {
var sum = 0;
if (values) {
for (var i = 0; i < values.length; i++) {
sum += 1;
}
}
return {sala:sala, total:sum};
}
db.reservas.mapReduce(map, reduce, {"out":"resultado"})
###Problema: Quando existe apenas 1 reserva para uma sala, o reduce não é chamado:
db.resultado.find({})
{ "_id" : ObjectId("4fbd6d5b700f6e1266000002"), "value" : [ 1 ] }
{ "_id" : ObjectId("4fbd6e69700f6e1266000004"), "value" : { "sala" : ObjectId("4fbd6e69700f6e1266000004"), "total" : 2 } }
Aparentemente resuolvi usando uma function finalize:
finalize = function(key, values){ var total = 1; if(!values.length) total = values; return total; }E passei isso no runCommad:
db.runCommand({mapreduce: "reservas", map: map, reduce: reduce, out:"foo", finalize: finalize})E no resultado:
> db.foo.find({}) { "_id" : ObjectId("4fbd6d5b700f6e1266000002"), "value" : 1 } { "_id" : ObjectId("4fbd6e69700f6e1266000004"), "value" : 2 }Desta forma quando o reduce não for chamado no finalize eu trato tudo.
PS: ao invés de passar um [1] no emit estou passando apenas 1. Assim elimino o if no finalize.
PPS: se eu não precisar formatar a saída, então nem preciso do finalize. A saída que eu estava usando {sala: foo, total: bar} é a mesma que o próprio map/reduce já me retorna {key: foo, value: bar}