MongoDBでネストされたドキュメントを集約する方法【$unwindと$groupの使い方】
ネストされたドキュメントの集約に必要な演算子
MongoDBでネストされた(入れ子構造の)ドキュメントを集約するには、アグリゲーションフレームワークの $unwind と $group を組み合わせて使用します。$unwind は配列フィールドを個別のドキュメントへ展開するステージであり、$group は展開後のドキュメントをまとめて最大値・合計・平均などの集計を行うステージです。
サンプルコレクションの作成
まず、「ProductInformation」という配列の中に、さらに「Product1」という配列がネストされたドキュメントを持つコレクションを作成します。
> db.aggregateDemo.insertOne(
... {
... "ProductInformation": [
... {
... "Product1": [
... {
... Amount: 50
... },
... {
... Amount: 90
... },
... {
... Amount: 30
... }
... ]
... },
... {
... "Product1": [
... {
... Amount: 200
... },
... {
... Amount: 30
... },
... {
... Amount: 40
... }
... ]
... },
... {
... "Product1": [
... {
... Amount: 150
... },
... {
... Amount: 190
... },
... {
... Amount: 198
... }
... ]
... }
...
... ]
... });
{
"acknowledged" : true,
"insertedId" : ObjectId("5e04df58150ee0e76c06a04d")
}
> db.aggregateDemo.insertOne(
... {
... "ProductInformation": [
... {
... "Product1": [
... {
... Amount: 100
... },
... {
... Amount: 1002
... },
... {
... Amount: 78
... }
... ]
... },
... {
... "Product1": [
... {
... Amount: 75
... },
... {
... Amount: 400
... },
... {
... Amount: 600
... }
... ]
... },
... {
... "Product1": [
... {
... Amount: 700
... },
... {
... Amount: 500
... },
... {
... Amount: 600
... }
... ]
... }
...
... ]
... });
{
"acknowledged" : true,
"insertedId" : ObjectId("5e04df93150ee0e76c06a04e")
}2件のドキュメントが正常に挿入されました。続いて、find() メソッドを使って、コレクション内のすべてのドキュメントを確認してみましょう。
> db.aggregateDemo.find().pretty();
上記のクエリを実行すると、次のような出力が得られます。
{
"_id" : ObjectId("5e04df58150ee0e76c06a04d"),
"ProductInformation" : [
{
"Product1" : [
{
"Amount" : 50
},
{
"Amount" : 90
},
{
"Amount" : 30
}
]
},
{
"Product1" : [
{
"Amount" : 200
},
{
"Amount" : 30
},
{
"Amount" : 40
}
]
},
{
"Product1" : [
{
"Amount" : 150
},
{
"Amount" : 190
},
{
"Amount" : 198
}
]
}
]
}
{
"_id" : ObjectId("5e04df93150ee0e76c06a04e"),
"ProductInformation" : [
{
"Product1" : [
{
"Amount" : 100
},
{
"Amount" : 1002
},
{
"Amount" : 78
}
]
},
{
"Product1" : [
{
"Amount" : 75
},
{
"Amount" : 400
},
{
"Amount" : 600
}
]
},
{
"Product1" : [
{
"Amount" : 700
},
{
"Amount" : 500
},
{
"Amount" : 600
}
]
}
]
}ネストされたドキュメントを集約するクエリ
ここからが本題です。ネストされた配列の中にある「Amount」フィールドの最大値を求める集約クエリは、以下のようになります。
> db.aggregateDemo.aggregate([
... {
... $unwind:"$ProductInformation"
... },
... {
... $unwind:"$ProductInformation.Product1"
... },
... {
... $group:{
... _id:null,
... MaximumAmount:{
... $max:"$ProductInformation.Product1.Amount"
... }
... }
... }
... ]);パイプラインの各ステージの動作
- 第1の $unwind:「ProductInformation」配列を展開し、要素ごとに個別のドキュメントへ分割します。
- 第2の $unwind:展開後の「ProductInformation.Product1」配列をさらに展開し、Amount の値を1つずつ持つフラットなドキュメントに変換します。
- $group:
_id: nullを指定することでコレクション内のすべてのドキュメントを1つのグループにまとめ、$max演算子によって「Amount」の最大値を計算します。
このクエリを実行すると、次のような結果が出力されます。
{ "_id" : null, "MaximumAmount" : 1002 }まとめ
ネストされた配列を集約する際のポイントは、$unwind を配列の階層の数だけ繰り返し適用することです。これにより、深い階層にある値もフラットな形式で扱えるようになり、その後 $group を使って自由に集計できるようになります。なお、_id: null はコレクション全体を1つのグループとして扱う指定です。カテゴリごとの集計などを行いたい場合は、_id に任意のフィールドを指定することで、グループ単位の集約も簡単に実現できます。
-
MongoDBでネストされた埋め込みドキュメントを更新する方法
MongoDBでネストされた埋め込みドキュメント(サブドキュメント)を更新するには、update()メソッドと位置演算子($)を使用します。位置演算子「$」は、クエリ条件に一致した配列要素を自動的に識別し、その要素だけを対象に更新処理を行える便利な機能です。コレクションの作成とドキュメントの挿入まず、insertOne()メソッドを使って、ネストされた構造を持つドキュメントを含むコレクションを作成しましょう。> db.demo643.insertOne({... details : [... {... CountryName:US,...
-
【MongoDB】ネストされたドキュメントのキー名のみを抽出して表示する方法
MongoDBでは、配列内にネストされたドキュメント(サブドキュメント)のキー名だけを一覧として取得したいケースがあります。本記事では、insertOne()でサンプルデータを作成し、find()で内容を確認した後、集計パイプラインの$reduce、$objectToArray、$map、$concatArraysを組み合わせて、ネストされたドキュメントのキー名のみを抽出する方法を実行例付きで解説します。 1. サンプルコレクションの作成 まず、insertOne()メソッドを使って、detailsフィールドに複数のドキュメントを持つ配列を含むコレクションを作成します。 > db.dem