また、ドキュメントによると、「MongoDB は、同じキーに対して reduce 関数を複数回呼び出すことができます。この場合、そのキーの reduce 関数からの以前の出力は、への入力値の 1 つになります。次に、そのキーの関数呼び出しを減らします。".
また、reduce
結合的、可換的、冪等でなければなりません。
reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] )
reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray )
reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )
したがって、reduce
関数は、それ自体の前回の呼び出しの結果であるオブジェクトを受け取る準備ができている必要があることを意味します。これは (少なくとも私にとっては個人的に) 実装する最善の方法mapReduce
は、map
(可能であれば)reduce
関数が返す値と同じ形式で値を発行するようにすることです。次に、reduce
1 つの入力形式のみをサポートするように関数を実装できます。その結果、 によって発行されたオブジェクトが 1 つしかない場合でもmap
(その結果、 の呼び出しreduce
がスキップされた場合)、 の最終結果ではmapReduce
、 が呼び出されなかったキーの値reduce
が引き続き に残ります。残りのキーの値と同じ形式。
たとえば、次のドキュメント構造があるとします。
{
"foo": <some_string>,
"status": ("foo"|"bar")
}
map
関数は次のようになります。
function() {
var value = {
"num_total": 1,
"num_foos": 0,
"num_bars": 0
};
if (this.status == "foo") {
value["num_foos"] += 1;
}
if (this.status == "bar") {
value["num_bars"] += 1;
}
emit(this.foo, value);
}
reduce
関数は次のようになります。
function(key, values) {
var reduced = {
"num_total": 0,
"num_foos": 0,
"num_bars": 0
};
values.forEach(function(val) {
reduced["num_total"] += val["num_total"];
reduced["num_foos"] += val["num_foos"];
reduced["num_bars"] += val["num_bars"];
});
return reduced;
}