db.collection.mapReduce()
注意
map-reduce の代替としての集計パイプライン
MongoDB 5.0以降、 map-reduceは非推奨です。
map-reduceの代わりに、集計パイプラインを使用する必要があります。 集計パイプラインは、map-reduce よりもパフォーマンスとユーザビリティが優れています。
$group
$merge
などの集約パイプライン ステージ を使用して、map-reduce操作を書き換えることができます。カスタム機能を必要とする map-reduce 操作には、
$accumulator
と$function
の集計演算子を使用できます。 これらの演算子を使用して、JavaScript でカスタム集計式を定義できます。
map-reduce を集計パイプラインに置き換える例については、以下を参照してください。
db.collection.mapReduce(map,reduce, { <options> })
重要
mongosh メソッド
このページでは、
mongosh
メソッドについて説明します。ただし、データベースコマンドや Node.js などの言語固有のドライバーのドキュメントには該当しません。データベースコマンドについては、
mapReduce
コマンドを参照してください。MongoDB API ドライバーについては、各言語の MongoDB ドライバー ドキュメントを参照してください。
注意
ビューでは map-reduce 操作をサポートしていません。
構文
注意
db.collection.mapReduce()
の構文は次のとおりです。
db.collection.mapReduce( <map>, <reduce>, { out: <collection>, query: <document>, sort: <document>, limit: <number>, finalize: <function>, scope: <document>, jsMode: <boolean>, verbose: <boolean>, bypassDocumentValidation: <boolean> } )
db.collection.mapReduce()
は以下のパラメーターを取ります。
Parameter | タイプ | 説明 |
---|---|---|
map | javascript または文字列 |
詳細については、 map 関数の要件 を参照してください。 |
reduce | javascript または文字列 | 特定の 詳細については、「 reduce 関数の要件 」を参照してください。 |
options | ドキュメント | db.collection.mapReduce() に追加のパラメータを指定するドキュメント。 |
次の表では、db.collection.mapReduce()
が受け入れることができる追加の引数について説明します。
フィールド | タイプ | 説明 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
out | 文字列またはドキュメント | |||||||||||
query | ドキュメント | map 関数への入力ドキュメントを決定するための選択基準をクエリ演算子を使用して指定します。 | ||||||||||
sort | ドキュメント | 入力ドキュメントを並べ替えます。このオプションは、最適化に役立ちます。たとえば、sort キーを emit キーと同じものに指定すると、reduce 操作の数を減らせます。sort キーは、このコレクションの既存のインデックス内になければなりません。 | ||||||||||
limit | 数値 | map 関数に入力するドキュメントの最大数を指定します。 | ||||||||||
finalize | javascript または文字列 | 任意。 詳細については、 finalize 関数の要件を参照してください。 | ||||||||||
scope | ドキュメント | map 、 reduce 、 finalize 関数でアクセス可能なグローバル変数を指定します。 | ||||||||||
jsMode | ブール値 |
デフォルトは
| ||||||||||
verbose | ブール値 | 結果情報に デフォルトは このオプションは無視されます。結果情報には常に | ||||||||||
collation | ドキュメント | 任意。 操作に使用する照合を指定します。 照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。 照合オプションの構文は次のとおりです。
照合を指定する場合、 照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合( コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。 1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。 | ||||||||||
bypassDocumentValidation | ブール値 | 任意。 mapReduce を有効にすると、操作中にドキュメント検証をバイパスできます。これにより、検証要件を満たさないドキュメントを挿入できるようになります。 |
注意
map-reduce operations
および $where
演算子式は、mongosh
内で使用可能な db
などの特定のグローバル関数またはプロパティにアクセスできません 。
次の JavaScript 関数とプロパティは、map-reduce operations
および$where
演算子の式で使用できます。
利用可能なプロパティ | 利用可能な機能 | |
---|---|---|
args MaxKey MinKey | assert() BinData() DBPointer() DBRef() doassert() emit() gc() HexData() hex_md5() isNumber() isObject() ISODate() isString() | Map() MD5() NumberInt() NumberLong() ObjectId() print() printjson() printjsononeline() sleep() Timestamp() tojson() tojsononeline() tojsonObject() UUID() version() |
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 ] )
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 }
finalize
関数の要件
finalize
関数のプロトタイプは次のとおりです。
function(key, reducedValue) { ... return modifiedObject; }
finalize
関数は、引数としてkey
値とreduce
関数からのreducedValue
を受け取ります。 注意すること:
finalize
関数は、何らかの理由で データベースにアクセスしてはなりません。finalize
関数は純粋で、関数の外部に影響を与えないようにする必要があります( 副作用はありません。)finalize
関数は、scope
パラメータで定義された変数にアクセスできます。
map-reduce の例
このセクションの例には、カスタム集計式を使用しない集計パイプラインの代替手段が含まれています。カスタム式を使用する代替方法については「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 } }
出力
db.collection.mapReduce()
メソッドの出力はmapReduce
コマンドの出力と同じです。 出力の詳細については、 mapReduce
db.collection.mapReduce()
コマンドの 出力 セクションを参照してください。
制限事項
db.collection.mapReduce()
afterClusterTime のサポートを終了しました。このため、db.collection.mapReduce()
を因果一貫性のあるセッションに関連付けることはできません。