mapReduce
注意
map-reduce の代替としての集計パイプライン
MongoDB 5.0以降、 map-reduceは非推奨です。
map-reduceの代わりに、集計パイプラインを使用する必要があります。 集計パイプラインは、map-reduce よりもパフォーマンスとユーザビリティが優れています。
$group
$merge
などの集約パイプライン ステージ を使用して、map-reduce操作を書き換えることができます。カスタム機能を必要とする map-reduce 操作には、
$accumulator
と$function
の集計演算子を使用できます。 これらの演算子を使用して、JavaScript でカスタム集計式を定義できます。
map-reduce を集計パイプラインに置き換える例については、以下を参照してください。
定義
mapReduce
mapReduce
コマンドを使用すると、コレクションに対してmap-reduce集計操作を実行できます。Tip
mongosh
では、このコマンドはmapReduce()
ヘルパー メソッドを通じて実行することもできます。ヘルパー メソッドは
mongosh
ユーザーには便利ですが、データベースコマンドと同じレベルの情報は返されない可能性があります。 便宜上必要ない場合、または追加の戻りフィールドが必要な場合は、 データベースコマンドを使用します。
互換性
このコマンドは、次の環境でホストされている配置で使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
重要
このコマンドは、M 0 、M 2 、M 5クラスターではサポートされていません。 詳細については、「サポートされていないコマンド 」を参照してください。
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
注意
このコマンドの構文は、次のとおりです。
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 または文字列 |
詳細については、「 map 関数の要件 」を参照してください。 | |||||||||||
javascript または文字列 | 特定の 詳細については、「 reduce 関数の要件 」を参照してください。 | |||||||||||
文字列またはドキュメント | map-reduce 操作の結果を出力する場所を指定します。 コレクションに出力することも、結果をインラインで返すこともできます。 レプリカセットのプライマリでは、コレクションまたはインラインでの出力が可能ですが、セカンダリでは、インライン出力のみが可能です。 詳細については、「 アウト オプション 」を参照してください。 | |||||||||||
ドキュメント | 任意。 | |||||||||||
ドキュメント | 任意。入力ドキュメントを並べ替えます。このオプションは、最適化に役立ちます。例えば、sort キーを emit キーと同じものに指定すると、reduce 操作の数を減らせます。sort キーは、このコレクションの既存のインデックス内になければなりません。 | |||||||||||
数値 | 任意。 | |||||||||||
javascript または文字列 | 任意。 詳細については、「 finalize 関数の要件 」を参照してください。 | |||||||||||
ドキュメント | 任意。 | |||||||||||
ブール値 | 任意。 デフォルトは
| |||||||||||
ブール値 | ||||||||||||
ブール値 | ||||||||||||
ドキュメント | 任意。 操作に使用する照合を指定します。 照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。 照合オプションの構文は次のとおりです。
照合を指定する場合、 照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合( コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。 1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。 | |||||||||||
| non-negative integer | 任意。 時間制限をミリ秒単位で指定します。 MongoDB は、 | ||||||||||
ドキュメント | 任意。 コレクションに出力するときに使用する 書込み保証 ( write concern ) を表すドキュメント。 デフォルトの書込み保証を使用する場合は省略します。 | |||||||||||
| any | 任意。このコマンドに添付するユーザー指定のコメント。設定すると、このコメントは以下の場所にこのコマンドの記録と合わせて表示されます。
コメントには、有効な BSON 型(string, integer, object, array など)を使用できます。 |
使用法
以下は、 mapReduce
コマンドの使用プロトタイプです。
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
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 以降、次の機能が廃止されます。
新しいシャーディングされたコレクションを作成する ための map-reduce オプション、および、map-reduce のシャードオプションの使用。 シャーディングされたコレクションに出力するには、まずシャーディングされたコレクションを作成します。 MongoDB 4.2では、既存のシャーディングされたコレクションの置き換えも非推奨となります。ん。
このオプションは、すでに存在するコレクションを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 }
必要なアクセス権
MongoDB 配置で認証が強制される場合、 mapReduce
コマンドを実行するユーザーは次の特権アクションを持っている必要があります。
{out : inline}
出力オプションを使用した map-reduce の例:
コレクションに出力するときに、 replace
アクションを使用して map-reduce を実行します。
コレクションに出力するときに、 merge
またはreduce
アクションを使用して map-reduce を実行します。
readWrite
組み込みロール は、map-reduce 集計を実行するために必要な権限を提供します。
制限事項
mapReduce
コマンドはafterClusterTimeのサポートを終了しました。 このため、 mapReduce
は因果整合性のあるセッション に関連付けることはできません。
map-reduce の例
mongosh
では、 db.collection.mapReduce()
メソッドはmapReduce
コマンドのラッパーです。 次の例ではdb.collection.mapReduce()
メソッドを使用します。
このセクションの例には、カスタム集計式を使用しない集計パイプラインの代替手段が含まれています。カスタム式を使用する代替方法については「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" } ])
$group
ステージはcust_id
でグループ化し、value
フィールドを計算します($sum
も参照してください)。value
フィールドには、各cust_id
の合計price
が含まれます。このステージでは、次のドキュメントを次のステージに出力します。
{ "_id" : "Don Quis", "value" : 155 } { "_id" : "Ant O. Knee", "value" : 95 } { "_id" : "Cam Elot", "value" : 60 } { "_id" : "Busby Bee", "value" : 125 } 次に、
$out
により出力がコレクションagg_alternative_1
に書き込まれます。あるいは、$out
の代わりに$merge
を使用することもできます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 }
アイテムごとの平均数量で注文と合計数量を計算
次の例では、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 ] } $project
ステージでは、出力ドキュメントを再形成して、map-reduce の出力をミラーリングし、2 つのフィールド_id
とvalue
を含めます。$project
セット:$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 } }
詳細と例については、「 map-reduceページ 」および「 map-reduce の増分実行 」を参照してください
出力
結果をコレクションに書き込むようにアウトパラメーターを設定すると、 mapReduce
コマンドは次の形式のドキュメントを返します。
{ "result" : "map_reduce_example", "ok" : 1 }
アウトパラメータを設定して結果をインラインで出力すると、 mapReduce
コマンドは次の形式のドキュメントを返します。
{ "results" : [ { "_id" : <key>, "value" :<reduced or finalizedValue for key> }, ... ], "ok" : <int> }
mapReduce.result
コレクションに送信される出力の場合、この値は次のいずれかになります。
でデータベース名が指定されていない場合のコレクション名の string 、または
db
collection
データベース名とコレクション名の両方が指定さ れ ている場合は、 フィールドと フィールドの両方を含むドキュメント。
mapReduce.results
インラインで書き込まれた出力の場合、結果ドキュメントの配列。 結果の各ドキュメントには 2 つのフィールドが含まれています。
_id
フィールドにはkey
値が含まれており、value
フィールドには、関連付けられたkey
の減少または確定された値が含まれます。
mapReduce.ok
1
の値は、mapReduce
コマンドが正常に実行されたことを示します。 値が0
の場合はエラーを示します。
前述のコマンド固有の戻りフィールドに加えて、 db.runCommand()
には追加情報が含まれます。
レプリカ セットの場合、
$clusterTime
とoperationTime
。シャーディングされたクラスターの場合、
operationTime
および$clusterTime
。
これらのフィールドの詳細については db.runCommand レスポンスを参照してください。