注意
map-reduce の代替としての集計パイプライン
MongoDB 5.0 以降、map-reduce は非推奨になっています。
map-reduceの代わりに、集計パイプラインを使用する必要があります。 集計パイプラインは、map-reduce よりもパフォーマンスとユーザビリティが優れています。
map-reduce 操作は、
$group、$mergeなどの集計パイプライン ステージ を使用して書き換えることができます。カスタム機能を必要とする map-reduce 操作には、
$accumulatorと$functionの集計演算子を使用できます。 これらの演算子を使用して、JavaScript でカスタム集計式を定義できます。
map-reduce を集計パイプラインに置き換える例については、以下を参照してください。
定義
mapReduceコレクションに対してmap-reduce集計操作を実行します。
Tip
In
mongosh, this command can also be run through themapReduce()helper method.Helper methods are convenient for
mongoshusers, but they may not return the same level of information as database commands. In cases where the convenience is not needed or the additional return fields are required, use the database command.
互換性
このコマンドは、次の環境でホストされている配置で使用できます。
- MongoDB Atlas はクラウドでの MongoDB 配置のための完全管理サービスです
重要
このコマンドは、M0 および Flex クラスターではサポートされていません。詳細については、サポートされていないコマンド を参照してください。
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
注意
MongoDB は冗長オプションを無視します。
MongoDB バージョン 4.2 以降、次の機能が廃止されます。
- 新しいシャーディングされたコレクションを 作成する ためのmap-reduceオプション、および、 map-reduceの シャード オプションの使用。シャーディングされたコレクションに出力するには、まずシャーディングされたコレクションを作成します。 MongoDB.4 2は、既存のシャーディングされたコレクションの置き換えも非推奨とします。
このコマンドの構文は、次のとおりです。
db.runCommand( { mapReduce: <string>, map: <string or JavaScript>, reduce: <string or JavaScript>, finalize: <string or JavaScript>, out: <output>, query: <document>, sort: <document>, limit: <number>, scope: <document>, jsMode: <boolean>, verbose: <boolean>, bypassDocumentValidation: <boolean>, collation: <document>, maxTimeMS: <integer>, writeConcern: <document>, comment: <any> } )
コマンドフィールド
コマンドは、次のフィールドを引数として受け取ります。
フィールド | タイプ | 説明 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
string | map-reduce を実行するコレクションの名前。このコレクションは、 ビューでは map-reduce 操作をサポートしていません。 | |||||||||||
javascript または文字列 |
For more information, see Requirements for the map Function. | |||||||||||
javascript または文字列 | 特定の For more information, see Requirements for the reduce Function. | |||||||||||
文字列またはドキュメント | map-reduce 操作の結果を出力する場所を指定します。 コレクションに出力することも、結果をインラインで返すこともできます。 レプリカセットのプライマリでは、コレクションまたはインラインでの出力が可能ですが、セカンダリでは、インライン出力のみが可能です。 For more information, see out Options. | |||||||||||
ドキュメント | 任意。 | |||||||||||
ドキュメント | 任意。入力ドキュメントを並べ替えます。例えば、sort キーを emit キーと同じものに指定すると、reduce 操作の数を減らせます。sort キーは、このコレクションの既存のインデックス内になければなりません。 | |||||||||||
数値 | 任意。 | |||||||||||
javascript または文字列 | 任意。 For more information, see Requirements for the finalize Function. | |||||||||||
ドキュメント | 任意. | |||||||||||
ブール値 | 任意。 デフォルトは
| |||||||||||
ブール値 | 任意。結果情報に デフォルトは This option is ignored. The result information always excludes the | |||||||||||
ブール値 | Optional. Enables If the output option is set to | |||||||||||
ドキュメント | 任意。 任意。操作に使用する照合を指定します。 照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。 照合オプションの構文は次のとおりです。 照合を指定する場合、 照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合( コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。 1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。 | |||||||||||
| non-negative integer | 任意。 時間制限をミリ秒単位で指定します。 MongoDB は、 | ||||||||||
ドキュメント | 任意.コレクションに出力する際に使用する書込み保証 (write concern)を指定します。デフォルトの書込み保証 (write concern) を使用する場合は省略します。 | |||||||||||
| any | 任意。このコマンドに添付するユーザー指定のコメント。設定すると、このコメントは以下の場所にこのコマンドの記録と合わせて表示されます。
コメントには、有効な BSON 型(string, integer, object, array など)を使用できます。 |
使用法
The following is a prototype usage of the mapReduce command:
var mapFunction = function() { ... }; var reduceFunction = function(key, values) { ... }; db.runCommand( { mapReduce: <input-collection>, map: mapFunction, reduce: reduceFunction, out: { merge: <output-collection> }, query: <query> } )
注意
MongoDB の JavaScript
Although mapReduce uses JavaScript, most interactions with MongoDB do not use JavaScript but use an idiomatic driver in the language of the interacting application.
map 関数の要件
map関数は、各入力ドキュメントを 0 個以上のドキュメントに変換するのを担当します。 scopeパラメータで定義された変数にアクセスでき、次のプロトタイプがあります。
function() { ... emit(key, value); }
map関数には次の要件があります。
map関数は、関数内で現在のドキュメントをthisとして参照します。map関数は、何らかの理由で データベースにアクセスしてはなりません。map関数は純粋で、関数の外部に影響を与えないようにする必要があります( 副作用はありません。)map関数は任意に、任意の回数でemit(key,value)を呼び出して、keyをvalueに関連付ける出力ドキュメントを作成できます。
次のmap関数は、入力ドキュメントのstatusフィールドの値に応じてemit(key,value)を 0 回または 1 回呼び出します。
function() { if (this.status == 'A') emit(this.cust_id, 1); }
次のmap関数は、入力ドキュメントのitemsフィールドの要素数に応じて、 emit(key,value)を複数回呼び出す場合があります。
function() { this.items.forEach(function(item){ emit(item.sku, 1); }); }
reduce 関数の要件
reduce関数のプロトタイプは次のとおりです。
function(key, values) { ... return result; }
reduce関数は、次の動作を示します。
reduce関数は、読み取り操作を実行する場合でも、データベースにアクセスしないでください。reduce関数は外部システムに影響を与えないようにする必要があります。MongoDB では、同じキーに対して
reduce関数を複数回呼び出すことができます。 この場合、そのキーのreduce関数からの前回の出力は、そのキーの次のreduce関数を呼び出すへの入力値の 1 つになります。reduce関数は、scopeパラメータで定義された変数にアクセスできます。reduceへの入力は、MongoDB の最大 BSON ドキュメント サイズの半分を超えてはなりません。 この要件は、大きなドキュメントが返され、後続のreduceステップで結合された場合に違反される可能性があります。
同じキーに対してreduce関数を複数回呼び出すことができるため、次のプロパティが true である必要があります。
返されるオブジェクトの型は、
map関数によって出力されるvalueの型と同一である必要があります。reduce関数は連想である必要があります。 次のステートメントは true である必要があります。reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] ) reduce関数は冪等である必要があります。 次の文が true であることを確認します。reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray ) reduce関数はメンバーシップである必要があります 。つまり、valuesArray内の要素の順序はreduce関数の出力に影響を与えず、次のステートメントが当てはまります。reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )
finalize 関数の要件
finalize関数のプロトタイプは次のとおりです。
function(key, reducedValue) { ... return modifiedObject; }
finalize関数は、引数としてkey値とreduce関数からのreducedValueを受け取ります。 注意すること:
finalize関数は、何らかの理由で データベースにアクセスしてはなりません。finalize関数は純粋で、関数の外部に影響を与えないようにする必要があります( 副作用はありません。)finalize関数は、scopeパラメータで定義された変数にアクセスできます。
out オプション
outパラメータには次のオプションを指定できます。
コレクションへの出力
このオプションは新しいコレクションに出力し、レプリカセットのセカンダリ ノードでは使用できません。
out: <collectionName>
アクションを使用したコレクションへの出力
注意
MongoDB バージョン 4.2 以降、次の機能が廃止されます。
- The map-reduce option to create a new sharded collection as well as the use of the sharded option for map-reduce. To output to a sharded collection, create the sharded collection first. MongoDB 4.2 also deprecates the replacement of an existing sharded collection.
このオプションは、すでに存在するコレクションをoutに渡す場合にのみ使用できます。 レプリカセットの セカンダリ ノードでは使用できません。
out: { <action>: <collectionName> [, db: <dbName>] [, sharded: <boolean> ] }
アクションを使用してコレクションに出力する場合、 outには次のパラメータがあります。
<action>: 次のいずれかのアクションを指定します。replace<collectionName>のコレクションが存在する場合は、<collectionName>の内容を置き換えます。merge出力コレクションがすでに存在する場合は、新しい結果を既存の結果とマージします。 既存のドキュメントが新しい結果と同じキーを持っている場合は、その既存のドキュメントを上書きします。
reduce出力コレクションがすでに存在する場合は、新しい結果を既存の結果とマージします。 既存のドキュメントが新しい結果と同じキーを持つ場合は、新しいドキュメントと既存のドキュメントの両方に
reduce関数を適用し、既存のドキュメントを結果で上書きします。
db:任意。 map-reduce 操作で出力を書込むデータベースの名前。 デフォルトでは、これは入力コレクションと同じデータベースになります。
インラインでの出力
メモリ内で map-reduce 操作を実行し、結果を返します。 このオプションは、レプリカセットのセカンダリ ノードでoutのみ使用できるオプションです。
out: { inline: 1 }
必要なアクセス権
If your MongoDB deployment enforces authentication, the user executing the mapReduce command must possess the following privilege actions:
{out : inline}出力オプションを使用した map-reduce の例:
コレクションに出力するときに、 replaceアクションを使用して map-reduce を実行します。
コレクションに出力するときに、 mergeまたはreduceアクションを使用して map-reduce を実行します。
readWrite組み込みロール は、map-reduce 集計を実行するために必要な権限を提供します。
制限事項
The mapReduce command no longer supports afterClusterTime. As such, mapReduce cannot be associated with causally consistent sessions.
map-reduce の例
In mongosh, the db.collection.mapReduce() method is a wrapper around the mapReduce command. The following examples use the db.collection.mapReduce() method:
このセクションの例には、カスタム集計式を使用しない集計パイプラインの代替手段が含まれています。カスタム式を使用する代替方法については「map-reduce から集計パイプラインへの変換例」を参照してください。
次のドキュメントを含むサンプル コレクションordersを作成します。
db.orders.insertMany([ { _id: 1, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-01"), price: 25, items: [ { sku: "oranges", qty: 5, price: 2.5 }, { sku: "apples", qty: 5, price: 2.5 } ], status: "A" }, { _id: 2, cust_id: "Ant O. Knee", ord_date: new Date("2020-03-08"), price: 70, items: [ { sku: "oranges", qty: 8, price: 2.5 }, { sku: "chocolates", qty: 5, price: 10 } ], status: "A" }, { _id: 3, cust_id: "Busby Bee", ord_date: new Date("2020-03-08"), price: 50, items: [ { sku: "oranges", qty: 10, price: 2.5 }, { sku: "pears", qty: 10, price: 2.5 } ], status: "A" }, { _id: 4, cust_id: "Busby Bee", ord_date: new Date("2020-03-18"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 5, cust_id: "Busby Bee", ord_date: new Date("2020-03-19"), price: 50, items: [ { sku: "chocolates", qty: 5, price: 10 } ], status: "A"}, { _id: 6, cust_id: "Cam Elot", ord_date: new Date("2020-03-19"), price: 35, items: [ { sku: "carrots", qty: 10, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" }, { _id: 7, cust_id: "Cam Elot", ord_date: new Date("2020-03-20"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 8, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 75, items: [ { sku: "chocolates", qty: 5, price: 10 }, { sku: "apples", qty: 10, price: 2.5 } ], status: "A" }, { _id: 9, cust_id: "Don Quis", ord_date: new Date("2020-03-20"), price: 55, items: [ { sku: "carrots", qty: 5, price: 1.0 }, { sku: "apples", qty: 10, price: 2.5 }, { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" }, { _id: 10, cust_id: "Don Quis", ord_date: new Date("2020-03-23"), price: 25, items: [ { sku: "oranges", qty: 10, price: 2.5 } ], status: "A" } ])
カスタマーあたりの合計価格を返す
orders コレクションに対して map-reduce 操作を実行して、cust_idごとにグループ化し、各cust_id の price の合計値を計算します。
各入力ドキュメントを処理する map 関数を定義します。
この関数では、
thisは map-reduce 操作で処理中のドキュメントを参照します。この関数は、各ドキュメントの
priceをcust_idにマッピングし、cust_idとpriceを出力します。
var mapFunction1 = function() { emit(this.cust_id, this.price); }; 2つの引数
keyCustIdとvaluesPricesを使用して、対応する reduce 関数を定義します。valuesPricesは、map 関数によって出力され、keyCustIdでグループ化されたprice値を要素とする配列です。この関数は
valuesPrice配列をその要素の合計にまで減らします。
var reduceFunction1 = function(keyCustId, valuesPrices) { return Array.sum(valuesPrices); }; ordersコレクション内のすべてのドキュメントに対して、map 関数mapFunction1と reduce 関数reduceFunction1を使用して map-reduce を実行します。db.orders.mapReduce( mapFunction1, reduceFunction1, { out: "map_reduce_example" } ) この操作は、結果を
map_reduce_exampleという名前のコレクションに出力します。map_reduce_exampleコレクションがすでに存在する場合、この操作により、内容が map-reduce 操作の結果に置き換えられます。map_reduce_exampleコレクションをクエリして、結果を検証します。db.map_reduce_example.find().sort( { _id: 1 } ) この操作では、次のドキュメントが返されます。
{ "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Busby Bee", "value" : 125 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Don Quis", "value" : 155 }
集計の代替手段
次のとおり利用可能な集約パイプライン演算子を使用すると、カスタム関数を定義しなくても map-reduce 操作を書き換えることができます。
db.orders.aggregate([ { $group: { _id: "$cust_id", value: { $sum: "$price" } } }, { $out: "agg_alternative_1" } ])
agg_alternative_1コレクションをクエリして、結果を検証します。db.agg_alternative_1.find().sort( { _id: 1 } ) この操作により、次のドキュメントが返されます。
{ "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Busby Bee", "value" : 125 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Don Quis", "value" : 155 }
Tip
カスタム集計式を使用する代替方法については、「Map-Reduceから集約パイプラインへの変換例」を参照してください。
アイテムごとの平均数量で注文と合計数量を計算
次の例では、orders 上でord_date の値が 2020-03-01 以上となるすべてのドキュメントについての map-reduce 操作を示します。
この例での操作は次のとおりです。
item.skuフィールドでグループ化し、各skuの注文数と合計注文数量を計算します。各
sku値について、1 回の注文あたりの平均数量を計算し、結果を出力コレクションにマージします。
結果をマージするときに、既存のドキュメントが新しい結果と同じキーを持っている場合、操作によって既存のドキュメントが上書きされます。同じキーを持つ既存のドキュメントが存在しない場合は、この操作によってドキュメントが挿入されます。
手順の例:
各入力ドキュメントを処理する map 関数を定義します。
この関数では、
thisは map-reduce 操作で処理中のドキュメントを参照します。各アイテムについて、この関数では
skuをcountが1の新規オブジェクトvalue、および注文アイテムのqtyとと関連付け、sku(keyに格納)とvalueを出力します。
var mapFunction2 = function() { for (var idx = 0; idx < this.items.length; idx++) { var key = this.items[idx].sku; var value = { count: 1, qty: this.items[idx].qty }; emit(key, value); } }; 2つの引数
keySKUとcountObjValsを使用して、対応する reduce 関数を定義します。countObjValsは、map 関数によって reducer 関数に渡される、グループ化されたkeySKU値にマップされたオブジェクトを要素とする配列です。この関数は
countObjVals配列をcountフィールドとqtyフィールドを含む 1 つのオブジェクトreducedValueに縮小します。reducedValでは、countフィールドには個々の配列エレメントのcountフィールドの合計が含まれ、qtyフィールドには個々の配列エレメントのqtyフィールドの合計が含まれます。
var reduceFunction2 = function(keySKU, countObjVals) { reducedVal = { count: 0, qty: 0 }; for (var idx = 0; idx < countObjVals.length; idx++) { reducedVal.count += countObjVals[idx].count; reducedVal.qty += countObjVals[idx].qty; } return reducedVal; }; 2 つの引数
keyとreducedValを持つ finalize 関数を定義します。この関数は、reducedValオブジェクトを変更してavgという名前の計算フィールドを追加し、変更されたオブジェクトを返します。var finalizeFunction2 = function (key, reducedVal) { reducedVal.avg = reducedVal.qty/reducedVal.count; return reducedVal; }; ordersコレクションに対して map-reduce 操作を実行するには、mapFunction2、reduceFunction2、およびfinalizeFunction2関数を使用します。db.orders.mapReduce( mapFunction2, reduceFunction2, { out: { merge: "map_reduce_example2" }, query: { ord_date: { $gte: new Date("2020-03-01") } }, finalize: finalizeFunction2 } ); この操作では、
queryフィールドを使用して、ord_dateの値がnew Date("2020-03-01")以上のドキュメントのみを選択します。次に、結果をコレクションmap_reduce_example2に出力します。map_reduce_example2コレクションがすでに存在する場合、この操作により、内容が map-reduce 操作の結果に置き換えられます。つまり既存のドキュメントが新しい結果と同じキーを持っている場合、操作によって既存のドキュメントが上書きされます。同じキーを持つ既存のドキュメントが存在しない場合は、この操作によってドキュメントが挿入されます。map_reduce_example2コレクションをクエリして、結果を検証します。db.map_reduce_example2.find().sort( { _id: 1 } ) この操作では、次のドキュメントが返されます。
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }
集計の代替手段
次のとおり利用可能な集約パイプライン演算子を使用すると、カスタム関数を定義しなくても map-reduce 操作を書き換えることができます。
db.orders.aggregate( [ { $match: { ord_date: { $gte: new Date("2020-03-01") } } }, { $unwind: "$items" }, { $group: { _id: "$items.sku", qty: { $sum: "$items.qty" }, orders_ids: { $addToSet: "$_id" } } }, { $project: { value: { count: { $size: "$orders_ids" }, qty: "$qty", avg: { $divide: [ "$qty", { $size: "$orders_ids" } ] } } } }, { $merge: { into: "agg_alternative_3", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } } ] )
$matchステージでは、ord_dateがnew Date("2020-03-01")以上であるドキュメントのみが選択されます。$unwindステージでは、items配列フィールドでドキュメントを分割して、配列要素ごとにドキュメントを出力します。たとえば:{ "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "apples", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "oranges", "qty" : 8, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "pears", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 4, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-18T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 5, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-19T00:00:00Z"), "price" : 50, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } ... $groupステージでは各 SKU について計算し、items.skuでグループ化します。qtyフィールド。qtyフィールドには次が含まれます。- 各
items.skuごとに注文されたqtyの合計($sumを参照)。
orders_ids配列。orders_idsフィールドには次が含まれます。items.skuについての、個別の注文の_id($addToSetを参照してください)。
{ "_id" : "chocolates", "qty" : 15, "orders_ids" : [ 2, 5, 8 ] } { "_id" : "oranges", "qty" : 63, "orders_ids" : [ 4, 7, 3, 2, 9, 1, 10 ] } { "_id" : "carrots", "qty" : 15, "orders_ids" : [ 6, 9 ] } { "_id" : "apples", "qty" : 35, "orders_ids" : [ 9, 8, 1, 6 ] } { "_id" : "pears", "qty" : 10, "orders_ids" : [ 3 ] } $unwindステージでは、items配列フィールドでドキュメントを分割して、配列要素ごとにドキュメントを出力します。たとえば:{ "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 1, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-01T00:00:00Z"), "price" : 25, "items" : { "sku" : "apples", "qty" : 5, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "oranges", "qty" : 8, "price" : 2.5 }, "status" : "A" } { "_id" : 2, "cust_id" : "Ant O. Knee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 70, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 3, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-08T00:00:00Z"), "price" : 50, "items" : { "sku" : "pears", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 4, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-18T00:00:00Z"), "price" : 25, "items" : { "sku" : "oranges", "qty" : 10, "price" : 2.5 }, "status" : "A" } { "_id" : 5, "cust_id" : "Busby Bee", "ord_date" : ISODate("2020-03-19T00:00:00Z"), "price" : 50, "items" : { "sku" : "chocolates", "qty" : 5, "price" : 10 }, "status" : "A" } ... $groupステージでは各 SKU について計算し、items.skuでグループ化します。qtyフィールド。qtyフィールドには、$sumにより、各items.skuごとに注文されたqtyの合計が含まれます。orders_ids配列。orders_idsフィールドには、$addToSetにより、items.skuについての個別の注文_idの配列が含まれます。
{ "_id" : "chocolates", "qty" : 15, "orders_ids" : [ 2, 5, 8 ] } { "_id" : "oranges", "qty" : 63, "orders_ids" : [ 4, 7, 3, 2, 9, 1, 10 ] } { "_id" : "carrots", "qty" : 15, "orders_ids" : [ 6, 9 ] } { "_id" : "apples", "qty" : 35, "orders_ids" : [ 9, 8, 1, 6 ] } { "_id" : "pears", "qty" : 10, "orders_ids" : [ 3 ] } $projectステージでは、出力ドキュメントを再形成して、map-reduce の出力をミラーリングし、2 つのフィールド_idとvalueを含めます。$projectセット:$sizeを使用して、value.countをorders_ids配列のサイズに合わせます入力ドキュメントの
qtyフィールドについてのvalue.qty。
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } 最後に、
$mergeは出力をコレクションagg_alternative_3に書き込みます。既存のドキュメントに新しい結果と同じキー_idがある場合、この操作によって既存のドキュメントが上書きされます。 同じキーを持つ既存のドキュメントが存在しない場合は、この操作によってドキュメントが挿入されます。agg_alternative_3コレクションをクエリして、結果を検証します。db.agg_alternative_3.find().sort( { _id: 1 } ) この操作により、次のドキュメントが返されます。
{ "_id" : "apples", "value" : { "count" : 4, "qty" : 35, "avg" : 8.75 } } { "_id" : "carrots", "value" : { "count" : 2, "qty" : 15, "avg" : 7.5 } } { "_id" : "chocolates", "value" : { "count" : 3, "qty" : 15, "avg" : 5 } } { "_id" : "oranges", "value" : { "count" : 7, "qty" : 63, "avg" : 9 } } { "_id" : "pears", "value" : { "count" : 1, "qty" : 10, "avg" : 10 } }
Tip
カスタム集計式を使用する代替方法については、「Map-Reduceから集約パイプラインへの変換例」を参照してください。
詳細と例については、「 map-reduceページ 」および「 map-reduce の増分実行 」を参照してください
出力
If you set the out parameter to write the results to a collection, the mapReduce command returns a document in the following form:
{ "result" : "map_reduce_example", "ok" : 1 }
If you set the out parameter to output the results inline, the mapReduce command returns a document in the following form:
{ "results" : [ { "_id" : <key>, "value" :<reduced or finalizedValue for key> }, ... ], "ok" : <int> }
mapReduce.resultコレクションに送信される出力の場合、この値は次のいずれかになります。
でデータベース名が指定されていない場合のコレクション名の string 、または
dbcollectionデータベース名とコレクション名の両方が指定さ れ ている場合は、 フィールドと フィールドの両方を含むドキュメント。
mapReduce.resultsインラインで書き込まれた出力の場合、結果ドキュメントの配列。 結果の各ドキュメントには 2 つのフィールドが含まれています。
_idフィールドにはkey値が含まれており、valueフィールドには、関連付けられたkeyの減少または確定された値が含まれます。
mapReduce.okA value of
1indicates themapReducecommand ran successfully. A value of0indicates an error.
上記のコマンド固有の戻りフィールドに加えて、 db.runCommand()には追加情報が含まれます。
レプリカ セットの場合、
$clusterTimeとoperationTime。シャーディングされたクラスターの場合、
operationTimeおよび$clusterTime。
これらのフィールドの詳細については db.runCommand レスポンスを参照してください。