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 つのオブジェクトに削減する 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 }