调试 Reduce 函数
注意
聚合管道作为 Map-Reduce 的替代方案
从 MongoDB 5.0 开始,map-reduce 已弃用
不再使用 map-reduce,您应使用 聚合管道。聚合管道比 map-reduce 提供更好的性能和可用性。
对于需要自定义功能的map-reduce操作,您可以使用
$accumulator和$function聚合运算符。您可以使用这些运算符在JavaScript中定义自定义的聚合表达式。
有关聚合管道替代map-reduce的示例,请参阅
与map-reduce操作相比,聚合管道更容易调试。
reduce函数是一个JavaScript函数,它在map-reduce操作期间将特定键关联的所有值“减少”为单个对象。reduce函数必须满足各种要求。本教程帮助验证reduce函数是否符合以下标准
reduce函数必须返回一个对象,其类型必须与map函数发出的
value的类型相同。valuesArray中元素的顺序不应影响reduce函数的输出。
reduce函数必须是幂等的。
有关reduce函数的所有要求的列表,请参阅mapReduce,或mongosh辅助方法db.collection.mapReduce()。
确认输出类型
您可以通过测试来验证reduce函数返回的值与来自map函数的值具有相同的类型。
定义一个名为
reduceFunction1的函数,该函数接收参数keyCustId和valuesPrices。其中,valuesPrices是一个整数数组。var reduceFunction1 = function(keyCustId, valuesPrices) { return Array.sum(valuesPrices); }; 定义一个整数的样本数组。
var myTestValues = [ 5, 5, 10 ]; 使用
myTestValues调用reduceFunction1。reduceFunction1('myKey', myTestValues); 验证
reduceFunction1返回了一个整数。20 定义一个名为
reduceFunction2的函数,该函数接收参数keySKU和valuesCountObjects。其中,valuesCountObjects是一个包含两个字段count和qty的文档数组。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; }; 定义一个文档的样本数组。
var myTestObjects = [ { count: 1, qty: 5 }, { count: 2, qty: 10 }, { count: 3, qty: 15 } ]; 使用
myTestObjects调用reduceFunction2。reduceFunction2('myKey', myTestObjects); 验证
reduceFunction2返回了一个包含正好count和qty字段的文档。{ "count" : 6, "qty" : 30 }
确保对映射值的顺序不敏感
reduce 函数接收一个 key 和一个 values 数组作为参数。您可以测试 reduce 函数的结果是否依赖于 values 数组中元素的顺序。
定义一个样本的
values1数组和一个样本的values2数组,这两个数组仅在数组元素的顺序上有所不同。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 } ]; 定义一个名为
reduceFunction2的函数,该函数接收参数keySKU和valuesCountObjects。其中,valuesCountObjects是一个包含两个字段count和qty的文档数组。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; }; 首先使用
values1调用reduceFunction2,然后使用values2调用。reduceFunction2('myKey', values1); reduceFunction2('myKey', values2); 验证
reduceFunction2返回了相同的结果。{ "count" : 6, "qty" : 30 }
确保 Reduce 函数幂等性
由于映射-归约操作可能会对同一个键调用多次reduce,并且对于工作集中单个实例的键不会调用reduce,因此reduce函数必须返回与从map函数发出的值相同类型的值。您可以测试reduce函数处理“归约”值而不影响最终值。
定义一个名为
reduceFunction2的函数,该函数接收参数keySKU和valuesCountObjects。其中,valuesCountObjects是一个包含两个字段count和qty的文档数组。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; }; 定义一个示例键
var myKey = 'myKey'; 定义一个示例
valuesIdempotent数组,该数组包含对reduceFunction2函数的调用元素var valuesIdempotent = [ { count: 1, qty: 5 }, { count: 2, qty: 10 }, reduceFunction2(myKey, [ { count:3, qty: 15 } ] ) ]; 定义一个示例
values1数组,该数组结合了传递给reduceFunction2的值var values1 = [ { count: 1, qty: 5 }, { count: 2, qty: 10 }, { count: 3, qty: 15 } ]; 首先使用
myKey和valuesIdempotent调用reduceFunction2,然后使用myKey和values1调用reduceFunction2(myKey, valuesIdempotent); reduceFunction2(myKey, values1); 验证
reduceFunction2返回了相同的结果。{ "count" : 6, "qty" : 30 }