Troubleshoot the Reduce Function
The reduce
function is a JavaScript function that “reduces” to asingle object all the values associated with a particular key during amap-reduce operation. The reduce
functionmust meet various requirements. This tutorial helps verify that thereduce
function meets the following criteria:
- The
reduce
function must return an object whose type must beidentical to the type of thevalue
emitted by themap
function. - The order of the elements in the
valuesArray
should not affectthe output of thereduce
function. - The
reduce
function must be idempotent.
For a list of all the requirements for the reduce
function, seemapReduce
, or the mongo
shell helper methoddb.collection.mapReduce()
.
Note
Starting in version 4.2.1, MongoDB deprecates the use of JavaScriptwith scope (i.e. BSON type 15) forthe map
, reduce
, and finalize
functions. To scopevariables, use the scope
parameter instead.
Confirm Output Type
You can test that the reduce
function returns a value that is thesame type as the value emitted from the map
function.
- Define a
reduceFunction1
function that takes the argumentskeyCustId
andvaluesPrices
.valuesPrices
is an array ofintegers:
- var reduceFunction1 = function(keyCustId, valuesPrices) {
- return Array.sum(valuesPrices);
- };
- Define a sample array of integers:
- var myTestValues = [ 5, 5, 10 ];
- Invoke the
reduceFunction1
withmyTestValues
:
- reduceFunction1('myKey', myTestValues);
- Verify the
reduceFunction1
returned an integer:
- 20
- Define a
reduceFunction2
function that takes the argumentskeySKU
andvaluesCountObjects
.valuesCountObjects
is an array ofdocuments that contain two fieldscount
andqty
:
- var reduceFunction2 = function(keySKU, valuesCountObjects) {
- reducedValue = { count: 0, qty: 0 };
- for (var idx = 0; idx < valuesCountObjects.length; idx++) {
- reducedValue.count += valuesCountObjects[idx].count;
- reducedValue.qty += valuesCountObjects[idx].qty;
- }
- return reducedValue;
- };
- Define a sample array of documents:
- var myTestObjects = [
- { count: 1, qty: 5 },
- { count: 2, qty: 10 },
- { count: 3, qty: 15 }
- ];
- Invoke the
reduceFunction2
withmyTestObjects
:
- reduceFunction2('myKey', myTestObjects);
- Verify the
reduceFunction2
returned a document with exactly thecount
and theqty
field:
- { "count" : 6, "qty" : 30 }
Ensure Insensitivity to the Order of Mapped Values
The reduce
function takes a key
and a values
array as itsargument. You can test that the result of the reduce
function doesnot depend on the order of the elements in the values
array.
- Define a sample
values1
array and a samplevalues2
arraythat only differ in the order of the array elements:
- var values1 = [
- { count: 1, qty: 5 },
- { count: 2, qty: 10 },
- { count: 3, qty: 15 }
- ];
- var values2 = [
- { count: 3, qty: 15 },
- { count: 1, qty: 5 },
- { count: 2, qty: 10 }
- ];
- Define a
reduceFunction2
function that takes the argumentskeySKU
andvaluesCountObjects
.valuesCountObjects
is an array ofdocuments that contain two fieldscount
andqty
:
- var reduceFunction2 = function(keySKU, valuesCountObjects) {
- reducedValue = { count: 0, qty: 0 };
- for (var idx = 0; idx < valuesCountObjects.length; idx++) {
- reducedValue.count += valuesCountObjects[idx].count;
- reducedValue.qty += valuesCountObjects[idx].qty;
- }
- return reducedValue;
- };
- Invoke the
reduceFunction2
first withvalues1
and then withvalues2
:
- reduceFunction2('myKey', values1);
- reduceFunction2('myKey', values2);
- Verify the
reduceFunction2
returned the same result:
- { "count" : 6, "qty" : 30 }
Ensure Reduce Function Idempotence
Because the map-reduce operation may call a reduce
multiple timesfor the same key, and won’t call a reduce
for single instancesof a key in the working set, the reduce
function must return a value of thesame type as the value emitted from the map
function. You can testthat the reduce
function process “reduced” values withoutaffecting the final value.
- Define a
reduceFunction2
function that takes the argumentskeySKU
andvaluesCountObjects
.valuesCountObjects
is an array ofdocuments that contain two fieldscount
andqty
:
- var reduceFunction2 = function(keySKU, valuesCountObjects) {
- reducedValue = { count: 0, qty: 0 };
- for (var idx = 0; idx < valuesCountObjects.length; idx++) {
- reducedValue.count += valuesCountObjects[idx].count;
- reducedValue.qty += valuesCountObjects[idx].qty;
- }
- return reducedValue;
- };
- Define a sample key:
- var myKey = 'myKey';
- Define a sample
valuesIdempotent
array that contains an element that is acall to thereduceFunction2
function:
- var valuesIdempotent = [
- { count: 1, qty: 5 },
- { count: 2, qty: 10 },
- reduceFunction2(myKey, [ { count:3, qty: 15 } ] )
- ];
- Define a sample
values1
array that combines the values passed toreduceFunction2
:
- var values1 = [
- { count: 1, qty: 5 },
- { count: 2, qty: 10 },
- { count: 3, qty: 15 }
- ];
- Invoke the
reduceFunction2
first withmyKey
andvaluesIdempotent
and then withmyKey
andvalues1
:
- reduceFunction2(myKey, valuesIdempotent);
- reduceFunction2(myKey, values1);
- Verify the
reduceFunction2
returned the same result:
- { "count" : 6, "qty" : 30 }