reduce 関数のトラブルシューティング
注意
map-reduce の代替としての集計パイプライン
MongoDB 5.0以降、 map-reduceは非推奨です。
map-reduceの代わりに、集計パイプラインを使用する必要があります。 集計パイプラインは、map-reduce よりもパフォーマンスとユーザビリティが優れています。
$group
$merge
などの集約パイプライン ステージ を使用して、map-reduce操作を書き換えることができます。カスタム機能を必要とする map-reduce 操作には、
$accumulator
と$function
の集計演算子を使用できます。 これらの演算子を使用して、JavaScript でカスタム集計式を定義できます。
map-reduce を集計パイプラインに置き換える例については、以下を参照してください。
また、map-reduce 操作よりも集計パイプラインの方がトラブルシューティングが簡単です。
reduce
関数は、 map-reduce操作中に特定のキーに関連付けられたすべての値を 1 つのオブジェクトに「reduce」するJavaScript関数です。 reduce
関数はさまざまな要件を満たしている必要があります。 このチュートリアルは、 reduce
関数が次の条件を満たしていることを確認するのに役立ちます。
reduce
関数は、map
関数によって出力されるvalue
の型と同一である必要があるオブジェクトを返す必要があります。valuesArray
内の要素の順序は、reduce
関数の出力には影響しません。reduce
関数は冪等である必要があります。
reduce
関数のすべての要件のリストについては、 mapReduce
または mongosh
ヘルパー メソッドdb.collection.mapReduce()
を参照してください。
出力タイプの確認
reduce
関数がmap
関数から出力する値と同じ型の値を返すことをテストできます。
keyCustId
とvaluesPrices
引数を持つreduceFunction1
関数を定義します。valuesPrices
は整数の配列です。var reduceFunction1 = function(keyCustId, valuesPrices) { return Array.sum(valuesPrices); }; 整数のサンプル配列を定義します。
var myTestValues = [ 5, 5, 10 ]; を使用して
reduceFunction1
myTestValues
を呼び出します。reduceFunction1('myKey', myTestValues); reduceFunction1
が整数を返したことを確認します。20 keySKU
とvaluesCountObjects
引数を持つreduceFunction2
関数を定義します。valuesCountObjects
は、2 つのフィールド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 } ]; keySKU
とvaluesCountObjects
引数を持つreduceFunction2
関数を定義します。valuesCountObjects
は、2 つのフィールド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 }
関数の冪等性を確実に減らす
map-reduce 操作では、同じキーに対してreduce
が複数回呼び出される可能性があり、ワーキングセット内のキーの単一のインスタンスに対してreduce
が呼び出されないため、 reduce
関数は次の値を返す必要があります: map
関数から出力される値と同じ型。 reduce
関数が最終値に影響を与えずに「削減された」値を処理することをテストできます。
keySKU
とvaluesCountObjects
引数を持つreduceFunction2
関数を定義します。valuesCountObjects
は、2 つのフィールド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'; reduceFunction2
関数の呼び出しである要素を含むサンプルvaluesIdempotent
配列を定義します。var valuesIdempotent = [ { count: 1, qty: 5 }, { count: 2, qty: 10 }, reduceFunction2(myKey, [ { count:3, qty: 15 } ] ) ]; reduceFunction2
に渡される値を組み合わせたサンプルvalues1
配列を定義します。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 }