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 ]; 使用
reduceFunction1
调用myTestValues
: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 } ]; 使用
reduceFunction2
调用myTestObjects
: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 函数幂等
由于 map-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 } ]; reduceFunction2
首先使用myKey
valuesIdempotent
myKey
和 ,然后使用 和 调用values1
:reduceFunction2(myKey, valuesIdempotent); reduceFunction2(myKey, values1); 验证
reduceFunction2
返回相同的结果:{ "count" : 6, "qty" : 30 }