Docs Menu
Docs Home
/
MongoDBマニュアル
/ / /

mapReduce

項目一覧

  • 定義
  • 互換性
  • 構文
  • コマンドフィールド
  • 使用法
  • 必要なアクセス権
  • 制限事項
  • map-reduce の例
  • 出力
  • 詳細情報

注意

map-reduce の代替としての集計パイプライン

MongoDB 5.0以降、 map-reduceは非推奨です。

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 のバージョン

注意

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関数によって処理される前に、 queryを使用してフィルタリングされます。

ビューでは map-reduce 操作をサポートしていません。

javascript または文字列

valuekey に関連付けたり「マッピング」したり、key と値 pair 値を出力したりする JavaScript 関数。関数は、BSON 型JavaScript(BSON 型 13)または文字列(BSON 型 2)として指定できます。

詳細については、「 map 関数の要件 」を参照してください。

javascript または文字列

特定のkeyに関連付けられているすべてのvaluesを 1 つのオブジェクトに「reduce」する JavaScript 関数。 関数は、 BSON型JavaScript ( BSON型 13)またはstring ( BSON型 2)として指定できます。

詳細については、「 reduce 関数の要件 」を参照してください。

文字列またはドキュメント

map-reduce 操作の結果を出力する場所を指定します。 コレクションに出力することも、結果をインラインで返すこともできます。 レプリカセットのプライマリでは、コレクションまたはインラインでの出力が可能ですが、セカンダリでは、インライン出力のみが可能です。

詳細については、「アウト オプション 」を参照してください。

ドキュメント

任意。map 関数への入力ドキュメントを決定するための選択基準をクエリ演算子を使用して指定します。

ドキュメント

任意。入力ドキュメントを並べ替えます。このオプションは、最適化に役立ちます。例えば、sort キーを emit キーと同じものに指定すると、reduce 操作の数を減らせます。sort キーは、このコレクションの既存のインデックス内になければなりません。

数値

任意。map 関数に入力するドキュメントの最大数を指定します。

javascript または文字列

任意。 reduce関数の後の出力を変更する JavaScript 関数。 関数は、 BSON型JavaScript ( BSON型 13)またはstring ( BSON型 2)として指定できます。

詳細については、「 finalize 関数の要件 」を参照してください。

ドキュメント

任意。mapreducefinalize 関数でアクセス可能なグローバル変数を指定します。

ブール値

任意。map 関数と reduce 関数の実行の間に中間データを BSON 形式に変換するかどうかを指定します。

デフォルトは false です。

false場合:

  • MongoDB は内部的に、 map関数によって出力された JavaScript オブジェクトを BSON オブジェクトに変換します。 これらの BSON オブジェクトは、 reduce関数を呼び出すときに JavaScript オブジェクトに変換されます。

  • map-reduce 操作は、中間 BSON オブジェクトを一時的なディスク上のストレージに配置します。 これにより、任意の大きなデータセットに対して map-reduce 操作を実行できます。

true場合:

  • 内部的には、 map関数中に発行される JavaScript オブジェクトは JavaScript オブジェクトとして残ります。 reduce関数のオブジェクトを変換する必要がないため、実行が高速化します。

  • jsModeは、マッパーのemit()関数への個別のkey引数が 500,000 未満の結果セットにのみ使用できます。

ブール値

任意。結果情報に timing 情報を含めるかどうかを指定します。verbosetrue に設定して、timing 情報を含めます。

デフォルトは false です。

このオプションは無視されます。結果情報には常にtiming 情報が除外されます。explain mapReduceモードまたは"executionStats" "allPlansExecution"verbosityモードで コマンドを使用して を実行中すると、タイミング情報を表示できます。

ブール値

任意。 操作中にmapReduceがドキュメント検証をバイパスできるようにします。 これにより、検証要件を満たさないドキュメントを挿入できるようになります。

出力オプションinlineに設定されている場合、ドキュメント検証は行われません。 出力がコレクションに送信される場合、 mapReduceはコレクションにある検証ルールを観察し、 bypassDocumentValidationパラメータが true に設定されていない限り、無効なドキュメントを挿入しません。

ドキュメント

任意。

操作に使用する照合を指定します。

照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。

照合オプションの構文は次のとおりです。

collation: {
locale: <string>,
caseLevel: <boolean>,
caseFirst: <string>,
strength: <int>,
numericOrdering: <boolean>,
alternate: <string>,
maxVariable: <string>,
backwards: <boolean>
}

照合を指定する場合、locale フィールドは必須ですが、その他の照合フィールドはすべて任意です。フィールドの説明については、照合ドキュメントを参照してください。

照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合(db.createCollection() を参照)には、コレクションの照合が使用されます。

コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。

1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。

maxTimeMS
non-negative integer

任意。

時間制限をミリ秒単位で指定します。maxTimeMS の値を指定しない場合、操作はタイムアウトしません。値を 0 にすると、デフォルトの無制限動作を明示的に指定します。

MongoDB は、db.killOp() と同じメカニズムを使用して、割り当てられた時間制限を超えた操作を終了します。MongoDB は、指定された割り込みポイントのいずれかでのみ操作を終了します。

ドキュメント

任意。 コレクションに出力するときに使用する 書込み保証 ( write concern ) を表すドキュメント。 デフォルトの書込み保証を使用する場合は省略します。

comment
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

mapReduceは JavaScript を使用しますが、MongoDB とのほとんどのやり取りでは JavaScript は使用されず、やり取りされるアプリケーションの言語で慣用的なドライバーが使用されます。

map関数は、各入力ドキュメントを 0 個以上のドキュメントに変換するのを担当します。 scopeパラメータで定義された変数にアクセスでき、次のプロトタイプがあります。

function() {
...
emit(key, value);
}

map関数には次の要件があります。

  • map関数は、関数内で現在のドキュメントをthisとして参照します。

  • map関数は、何らかの理由で データベースにアクセスしてはなりません

  • map関数は純粋で、関数の外部に影響を与えないようにする必要があります( 副作用はありません。)

  • map関数は任意に、任意の回数でemit(key,value)を呼び出して、 keyvalueに関連付ける出力ドキュメントを作成できます。

次の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関数のプロトタイプは次のとおりです。

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関数のプロトタイプは次のとおりです。

function(key, reducedValue) {
...
return modifiedObject;
}

finalize関数は、引数としてkey値とreduce関数からのreducedValueを受け取ります。 注意すること:

  • finalize関数は、何らかの理由で データベースにアクセスしてはなりません

  • finalize関数は純粋で、関数の外部に影響を与えないようにする必要があります( 副作用はありません。)

  • finalize関数は、 scopeパラメータで定義された変数にアクセスできます。

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 }

結果はBSON ドキュメントの最大サイズ内に収まる必要があります。

MongoDB 配置で認証が強制される場合、 mapReduceコマンドを実行するユーザーは次の特権アクションを持っている必要があります。

{out : inline}出力オプションを使用した map-reduce の例:

コレクションに出力するときに、 replaceアクションを使用して map-reduce を実行します。

コレクションに出力するときに、 mergeまたはreduceアクションを使用して map-reduce を実行します。

readWrite組み込みロール は、map-reduce 集計を実行するために必要な権限を提供します。

mapReduceコマンドはafterClusterTimeのサポートを終了しました。 このため、 mapReduce因果整合性のあるセッション に関連付けることはできません。

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_idprice の合計値を計算します。

  1. 各入力ドキュメントを処理する map 関数を定義します。

    • この関数では、 this は map-reduce 操作で処理中のドキュメントを参照します。

    • この関数は、各ドキュメントのpricecust_idにマッピングし、 cust_idpriceを出力します。

    var mapFunction1 = function() {
    emit(this.cust_id, this.price);
    };
  2. 2つの引数keyCustIdvaluesPricesを使用して、対応する reduce 関数を定義します。

    • valuesPricesは、map 関数によって出力され、keyCustIdでグループ化された price 値を要素とする配列です。

    • この関数は valuesPrice 配列をその要素の合計にまで減らします。

    var reduceFunction1 = function(keyCustId, valuesPrices) {
    return Array.sum(valuesPrices);
    };
  3. orders コレクション内のすべてのドキュメントに対して、map 関数 mapFunction1 と reduce 関数reduceFunction1 を使用して map-reduce を実行します。

    db.orders.mapReduce(
    mapFunction1,
    reduceFunction1,
    { out: "map_reduce_example" }
    )

    この操作は、結果をmap_reduce_exampleという名前のコレクションに出力します。map_reduce_exampleコレクションがすでに存在する場合、この操作により、内容が map-reduce 操作の結果に置き換えられます。

  4. 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" }
])
  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 }
  2. 次に、 $outにより出力がコレクションagg_alternative_1に書き込まれます。あるいは、 $out の代わりに$mergeを使用することもできます

  3. 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 操作を示します。

この例での操作は次のとおりです。

  1. item.skuフィールドでグループ化し、各 sku の注文数と合計注文数量を計算します。

  2. sku値について、1 回の注文あたりの平均数量を計算し、結果を出力コレクションにマージします。

結果をマージするときに、既存のドキュメントが新しい結果と同じキーを持っている場合、操作によって既存のドキュメントが上書きされます。同じキーを持つ既存のドキュメントが存在しない場合は、この操作によってドキュメントが挿入されます。

手順の例:

  1. 各入力ドキュメントを処理する map 関数を定義します。

    • この関数では、 this は map-reduce 操作で処理中のドキュメントを参照します。

    • 各アイテムについて、この関数では skucount1 の新規オブジェクト value 、および注文アイテムの qty とと関連付け、skukeyに格納)と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. 2つの引数keySKUcountObjValsを使用して、対応する 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;
    };
  3. 2 つの引数keyreducedValを持つ finalize 関数を定義します。この関数は、 reducedValオブジェクトを変更してavgという名前の計算フィールドを追加し、変更されたオブジェクトを返します。

    var finalizeFunction2 = function (key, reducedVal) {
    reducedVal.avg = reducedVal.qty/reducedVal.count;
    return reducedVal;
    };
  4. orders コレクションに対して map-reduce 操作を実行するには、mapFunction2reduceFunction2、および 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 操作の結果に置き換えられます。つまり既存のドキュメントが新しい結果と同じキーを持っている場合、操作によって既存のドキュメントが上書きされます。同じキーを持つ既存のドキュメントが存在しない場合は、この操作によってドキュメントが挿入されます。

  5. 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" } }
] )
  1. $matchステージでは、 ord_datenew Date("2020-03-01")以上であるドキュメントのみが選択されます。

  2. $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" }
    ...
  3. $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 ] }
  4. $projectステージでは、出力ドキュメントを再形成して、map-reduce の出力をミラーリングし、2 つのフィールド_idvalueを含めます。$projectセット:

  5. $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" }
    ...
  6. $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 ] }
  7. $projectステージでは、出力ドキュメントを再形成して、map-reduce の出力をミラーリングし、2 つのフィールド_idvalueを含めます。$projectセット:

    • $size を使用して、 value.countorders_ids配列のサイズに合わせます

    • 入力ドキュメントの qty フィールドについてのvalue.qty

    • $divide$sizeを使用して、 value.avgを注文あたりの平均数量に換算します。

    { "_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 } }
  8. 最後に、 $mergeは出力をコレクションagg_alternative_3に書き込みます。既存のドキュメントに新しい結果と同じキー_idがある場合、この操作によって既存のドキュメントが上書きされます。 同じキーを持つ既存のドキュメントが存在しない場合は、この操作によってドキュメントが挿入されます。

  9. 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 の増分実行 」を参照してください

結果をコレクションに書き込むようにアウトパラメーターを設定すると、 mapReduceコマンドは次の形式のドキュメントを返します。

{ "result" : "map_reduce_example", "ok" : 1 }

アウトパラメータを設定して結果をインラインで出力すると、 mapReduceコマンドは次の形式のドキュメントを返します。

{
"results" : [
{
"_id" : <key>,
"value" :<reduced or finalizedValue for key>
},
...
],
"ok" : <int>
}
mapReduce.result

コレクションに送信される出力の場合、この値は次のいずれかになります。

mapReduce.results

インラインで書き込まれた出力の場合、結果ドキュメントの配列。 結果の各ドキュメントには 2 つのフィールドが含まれています。

  • _id フィールドにはkey値が含まれており、

  • value フィールドには、関連付けられたkeyの減少または確定された値が含まれます。

mapReduce.ok

1の値は、 mapReduceコマンドが正常に実行されたことを示します。 値が0の場合はエラーを示します。

前述のコマンド固有の戻りフィールドに加えて、 db.runCommand()には追加情報が含まれます。

  • レプリカ セットの場合、 $clusterTimeoperationTime

  • シャーディングされたクラスターの場合、operationTimeおよび$clusterTime

これらのフィールドの詳細については db.runCommand レスポンスを参照してください。

戻る

distinct