En reduceringsfunktion kan anropas en gång, med en nyckel och alla motsvarande värden (men bara om det finns flera värden för nyckeln - den kommer inte att anropas alls om det bara finns ett värde för nyckeln).
Den kan också anropas flera gånger, varje gång med en nyckel och endast en delmängd av motsvarande värden , och föregående reducerar resultaten för den nyckeln. Det här scenariot kallas en re-reduce . För att stödja re-reduces bör din reducerfunktion vara idempotent.
Det finns två nyckelfunktioner i en idempotent reduceringsfunktion:
- returvärdet för reduceringsfunktionen ska vara i samma format som värdena Den tar in. Så om din reduceringsfunktion accepterar en array av strängar, bör funktionen returnera en sträng. Om den accepterar objekt med flera egenskaper, bör den returnera ett objekt som innehåller samma egenskaper. Detta säkerställer att funktionen inte går sönder när den anropas med resultatet av en tidigare reducering.
- Gör inte antaganden baserade på antalet värden det tar in. Det är inte garanterat att
values
parametern innehåller alla värdena för den givna nyckeln. Så användervalues.length
i beräkningar är mycket riskabelt och bör undvikas.
Uppdatering: De två stegen nedan är inte nödvändiga (eller ens möjliga, jag har inte kontrollerat) på de nyare MongoDB-utgåvorna. Den kan nu hantera dessa steg åt dig, om du anger en utdatasamling i kartförminskningsalternativen:
{ out: { reduce: "tempResult" } }
Om din reduceringsfunktion är idempotent bör du inte ha några problem med att kartreducera flera samlingar. Minska bara om resultaten för varje samling:
Steg 1
Kör map-reduce på varje önskad samling och spara resultaten i en enda, tillfällig samling. Du kan lagra resultaten med en slutföringsfunktion:
finalize = function (key, value) {
db.tempResult.save({ _id: key, value: value });
}
db.someCollection.mapReduce(map, reduce, { finalize: finalize })
db.anotherCollection.mapReduce(map, reduce, { finalize: finalize })
Steg 2
Kör en annan map-reduce på den temporära samlingen, med samma reduceringsfunktion . Kartfunktionen är en enkel funktion som väljer nycklar och värden från den tillfälliga samlingen:
map = function () {
emit(this._id, this.value);
}
db.tempResult.mapReduce(map, reduce)
Denna andra map-reduce är i grunden en re-reduce och bör ge dig de resultat du behöver.