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 the value emitted by the mapfunction.
  • The order of the elements in the valuesArray should not affectthe output of the reduce 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 and valuesPrices. valuesPrices is an array ofintegers:
  1. var reduceFunction1 = function(keyCustId, valuesPrices) {
  2. return Array.sum(valuesPrices);
  3. };
  • Define a sample array of integers:
  1. var myTestValues = [ 5, 5, 10 ];
  • Invoke the reduceFunction1 with myTestValues:
  1. reduceFunction1('myKey', myTestValues);
  • Verify the reduceFunction1 returned an integer:
  1. 20
  • Define a reduceFunction2 function that takes the argumentskeySKU and valuesCountObjects. valuesCountObjects is an array ofdocuments that contain two fields count and qty:
  1. var reduceFunction2 = function(keySKU, valuesCountObjects) {
  2. reducedValue = { count: 0, qty: 0 };
  3.  
  4. for (var idx = 0; idx < valuesCountObjects.length; idx++) {
  5. reducedValue.count += valuesCountObjects[idx].count;
  6. reducedValue.qty += valuesCountObjects[idx].qty;
  7. }
  8.  
  9. return reducedValue;
  10. };
  • Define a sample array of documents:
  1. var myTestObjects = [
  2. { count: 1, qty: 5 },
  3. { count: 2, qty: 10 },
  4. { count: 3, qty: 15 }
  5. ];
  • Invoke the reduceFunction2 with myTestObjects:
  1. reduceFunction2('myKey', myTestObjects);
  • Verify the reduceFunction2 returned a document with exactly thecount and the qty field:
  1. { "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 sample values2 arraythat only differ in the order of the array elements:
  1. var values1 = [
  2. { count: 1, qty: 5 },
  3. { count: 2, qty: 10 },
  4. { count: 3, qty: 15 }
  5. ];
  6.  
  7. var values2 = [
  8. { count: 3, qty: 15 },
  9. { count: 1, qty: 5 },
  10. { count: 2, qty: 10 }
  11. ];
  • Define a reduceFunction2 function that takes the argumentskeySKU and valuesCountObjects. valuesCountObjects is an array ofdocuments that contain two fields count and qty:
  1. var reduceFunction2 = function(keySKU, valuesCountObjects) {
  2. reducedValue = { count: 0, qty: 0 };
  3.  
  4. for (var idx = 0; idx < valuesCountObjects.length; idx++) {
  5. reducedValue.count += valuesCountObjects[idx].count;
  6. reducedValue.qty += valuesCountObjects[idx].qty;
  7. }
  8.  
  9. return reducedValue;
  10. };
  • Invoke the reduceFunction2 first with values1 and then withvalues2:
  1. reduceFunction2('myKey', values1);
  2. reduceFunction2('myKey', values2);
  • Verify the reduceFunction2 returned the same result:
  1. { "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 and valuesCountObjects. valuesCountObjects is an array ofdocuments that contain two fields count and qty:
  1. var reduceFunction2 = function(keySKU, valuesCountObjects) {
  2. reducedValue = { count: 0, qty: 0 };
  3.  
  4. for (var idx = 0; idx < valuesCountObjects.length; idx++) {
  5. reducedValue.count += valuesCountObjects[idx].count;
  6. reducedValue.qty += valuesCountObjects[idx].qty;
  7. }
  8.  
  9. return reducedValue;
  10. };
  • Define a sample key:
  1. var myKey = 'myKey';
  • Define a sample valuesIdempotent array that contains an element that is acall to the reduceFunction2 function:
  1. var valuesIdempotent = [
  2. { count: 1, qty: 5 },
  3. { count: 2, qty: 10 },
  4. reduceFunction2(myKey, [ { count:3, qty: 15 } ] )
  5. ];
  • Define a sample values1 array that combines the values passed toreduceFunction2:
  1. var values1 = [
  2. { count: 1, qty: 5 },
  3. { count: 2, qty: 10 },
  4. { count: 3, qty: 15 }
  5. ];
  • Invoke the reduceFunction2 first with myKey andvaluesIdempotent and then with myKey and values1:
  1. reduceFunction2(myKey, valuesIdempotent);
  2. reduceFunction2(myKey, values1);
  • Verify the reduceFunction2 returned the same result:
  1. { "count" : 6, "qty" : 30 }