$unwind(集計)
定義
互換性
次の環境でホストされる配置には $unwind
を使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
フィールドパス オペランドまたはドキュメント オペランドを渡して、配列フィールドを展開できます。
フィールドパス オペランド
配列フィールドパスを$unwind
に渡すことができます。 この構文を使用する場合、フィールド値が null、欠落、または空の配列である場合、 $unwind
はドキュメントを出力しません。
{ $unwind: <field path> }
フィールド パスを指定するときは、フィールド名の前にドル記号$
を付け、引用符で囲みます。
オプション付きドキュメント オペランド
バージョン 3.2 で追加。
ドキュメントを$unwind
に渡して、さまざまな動作オプションを指定できます。
{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
フィールド | タイプ | 説明 |
---|---|---|
string | 配列フィールドへのフィールドパス。フィールドパスを指定するには、フィールド名の前にドル記号 | |
string | 任意。要素の配列インデックスを保持する新しいフィールドの名前。名前をドル記号 | |
ブール値 |
動作
非配列フィールドパス
オペランドが配列に解決されないが、欠落しているわけでも
null
でもなく、または空の配列でもない場合、$unwind
はオペランドを単一要素の配列として扱います。オペランドが
null
か欠落しているか空の配列になっている場合、$unwind
では preserveNullAndEmptyArrays オプションに設定した動作に従います。
欠落しているフィールド
入力ドキュメントに存在しないフィールド、またはフィールドが空の配列であるフィールドのパスを指定すると、 $unwind
はデフォルトで入力ドキュメントを無視し、その入力ドキュメントのドキュメントを出力しません。
バージョン3.2の新機能: 配列フィールドが欠落しているか null か空の配列になっているドキュメントを出力するには、 preserveNullAndEmptyArraysオプションを使用します。
例
配列の展開
mongosh
では、次のドキュメントを含むinventory
という名前のサンプル コレクションが作成されます。
db.inventory.insertOne({ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })
次に示す集計では、$unwind
ステージを使用して、 sizes
配列にある要素ごとのドキュメントを出力します。
db.inventory.aggregate( [ { $unwind : "$sizes" } ] )
この操作は次の結果を返します。
{ "_id" : 1, "item" : "ABC1", "sizes" : "S" } { "_id" : 1, "item" : "ABC1", "sizes" : "M" } { "_id" : 1, "item" : "ABC1", "sizes" : "L" }
各ドキュメントは入力ドキュメントと同じですが、sizes
フィールドの値が元の sizes
配列の値に置き換えられています。
includeArrayIndex
および preserveNullAndEmptyArrays
バージョン 3.2 で追加。
mongosh
では、次のドキュメントを含むinventory2
という名前のサンプル コレクションが作成されます。
db.inventory2.insertMany([ { "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] }, { "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] }, { "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" }, { "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") }, { "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null } ])
次の$unwind
操作は同等であり、 sizes
フィールドの各要素のドキュメントを返します。 sizes
フィールドが配列に解決されず、欠落、値が null、または空の配列でもない場合、 $unwind
は配列以外のオペランドを単一要素の配列として扱います。
db.inventory2.aggregate( [ { $unwind: "$sizes" } ] ) db.inventory2.aggregate( [ { $unwind: { path: "$sizes" } } ] )
この操作により、次のドキュメントが返されます。
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" }
includeArrayIndex
次の$unwind
操作では、 includeArrayIndexオプションを使用して、出力に配列インデックスを含めます。
db.inventory2.aggregate( [ { $unwind: { path: "$sizes", includeArrayIndex: "arrayIndex" } }])
この操作はsizes
配列を展開し、 配列インデックスの配列インデックスを新しいarrayIndex
フィールドに含めます。 sizes
フィールドが配列に解決されず、欠落、値が null、または空の配列でもない場合、 arrayIndex
フィールドはnull
になります。
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S", "arrayIndex" : NumberLong(0) } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M", "arrayIndex" : NumberLong(1) } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L", "arrayIndex" : NumberLong(2) } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M", "arrayIndex" : null }
preserveNullAndEmptyArrays
次の$unwind
操作ではpreserveNullAndEmptyArraysオプションを使用して、 sizes
フィールドが null、欠落、または空の配列であるドキュメントを含めます。
db.inventory2.aggregate( [ { $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } } ] )
出力には、sizes
フィールドが null、欠落、または空の配列であるドキュメントが含まれます。
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" } { "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" } { "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") } { "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null }
展開された値によるグループ化
mongosh
では、次のドキュメントを含むinventory2
という名前のサンプル コレクションが作成されます。
db.inventory2.insertMany([ { "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] }, { "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] }, { "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" }, { "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") }, { "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null } ])
次のパイプラインでは sizes
配列を展開し、生成されたドキュメントを展開させたサイズ値でグループ化します。
db.inventory2.aggregate( [ // First Stage { $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }, // Second Stage { $group: { _id: "$sizes", averagePrice: { $avg: "$price" } } }, // Third Stage { $sort: { "averagePrice": -1 } } ] )
- 第 1 ステージ:
$unwind
ステージでは、sizes
配列の要素ごとに新しいドキュメントが出力されます。 ステージではpreserveNullAndEmptyArraysオプションを使用して、sizes
フィールドが欠落しているか null か空の配列になっているドキュメントを出力に含めます。 このステージでは、次のドキュメントを次のステージに渡します。{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" } { "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" } { "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") } { "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" } { "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") } { "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null } - 第 2 ステージ:
$group
ステージでは、ドキュメントをsizes
別にグループ化し、各サイズの平均価格を計算します。このステージでは、次のドキュメントを次のステージに渡します。{ "_id" : "S", "averagePrice" : NumberDecimal("80") } { "_id" : "L", "averagePrice" : NumberDecimal("80") } { "_id" : "M", "averagePrice" : NumberDecimal("120") } { "_id" : null, "averagePrice" : NumberDecimal("45.25") } - 第 3 ステージ:
$sort
ステージでは、ドキュメントをaveragePrice
の降順でソートします この操作では、次の結果を返します。{ "_id" : "M", "averagePrice" : NumberDecimal("120") } { "_id" : "L", "averagePrice" : NumberDecimal("80") } { "_id" : "S", "averagePrice" : NumberDecimal("80") } { "_id" : null, "averagePrice" : NumberDecimal("45.25") }
埋め込まれた配列の展開
mongosh
では、次のドキュメントを含むsales
という名前のサンプル コレクションが作成されます。
db.sales.insertMany([ { _id: "1", "items" : [ { "name" : "pens", "tags" : [ "writing", "office", "school", "stationary" ], "price" : NumberDecimal("12.00"), "quantity" : NumberInt("5") }, { "name" : "envelopes", "tags" : [ "stationary", "office" ], "price" : NumberDecimal("19.95"), "quantity" : NumberInt("8") } ] }, { _id: "2", "items" : [ { "name" : "laptop", "tags" : [ "office", "electronics" ], "price" : NumberDecimal("800.00"), "quantity" : NumberInt("1") }, { "name" : "notepad", "tags" : [ "stationary", "school" ], "price" : NumberDecimal("14.95"), "quantity" : NumberInt("3") } ] } ])
次の操作では、販売された商品をタグごとにグループ化し、タグごとに合計販売額を計算します。
db.sales.aggregate([ // First Stage { $unwind: "$items" }, // Second Stage { $unwind: "$items.tags" }, // Third Stage { $group: { _id: "$items.tags", totalSalesAmount: { $sum: { $multiply: [ "$items.price", "$items.quantity" ] } } } } ])
- 第 1 ステージ
1 つ目の
$unwind
ステージでは、新しいドキュメントが次のようにitems
配列の要素ごとに出力されます。{ "_id" : "1", "items" : { "name" : "pens", "tags" : [ "writing", "office", "school", "stationary" ], "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : [ "stationary", "office" ], "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : [ "office", "electronics" ], "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : [ "stationary", "school" ], "price" : NumberDecimal("14.95"), "quantity" : 3 } } - 第 2 ステージ
2 つ目の
$unwind
ステージでは、新しいドキュメントが次のようにitems.tags
配列の要素ごとに出力されます。{ "_id" : "1", "items" : { "name" : "pens", "tags" : "writing", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "office", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "school", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "pens", "tags" : "stationary", "price" : NumberDecimal("12.00"), "quantity" : 5 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : "stationary", "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "1", "items" : { "name" : "envelopes", "tags" : "office", "price" : NumberDecimal("19.95"), "quantity" : 8 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : "office", "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "laptop", "tags" : "electronics", "price" : NumberDecimal("800.00"), "quantity" : 1 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : "stationary", "price" : NumberDecimal("14.95"), "quantity" : 3 } } { "_id" : "2", "items" : { "name" : "notepad", "tags" : "school", "price" : NumberDecimal("14.95"), "quantity" : 3 } } - 第 3 ステージ
$group
ステージでは、ドキュメントをタグ別にグループ化し、各タグが付いたアイテムの合計売上額を計算します。{ "_id" : "writing", "totalSalesAmount" : NumberDecimal("60.00") } { "_id" : "stationary", "totalSalesAmount" : NumberDecimal("264.45") } { "_id" : "electronics", "totalSalesAmount" : NumberDecimal("800.00") } { "_id" : "school", "totalSalesAmount" : NumberDecimal("104.85") } { "_id" : "office", "totalSalesAmount" : NumberDecimal("1019.60") }