MongoDBの$$ROOTを使ってコレクション全体との比較に基づきドキュメントを抽出する方法
MongoDBでは、集計パイプライン(Aggregation Pipeline)内で $$ROOT 変数を利用すると、ドキュメント全体を参照できます。本記事では、この$$ROOTを活用して、コレクション全体との比較に基づいてドキュメント全体を抽出する方法を、具体的なサンプルコードとともにわかりやすく解説します。
サンプルコレクションの作成
まず、デモ用のコレクション「demo743」にドキュメントを挿入します。ドキュメントの登録には insertOne() メソッドを使用します。
> db.demo743.insertOne({id:1,"ShippingDate":"2020-01-21",value:50});
{
"acknowledged" : true,
"insertedId" : ObjectId("5ead893a57bb72a10bcf0680")
}
> db.demo743.insertOne({id:2,"ShippingDate":"2020-05-10",value:30});
{
"acknowledged" : true,
"insertedId" : ObjectId("5ead893c57bb72a10bcf0681")
}
> db.demo743.insertOne({id:3,"ShippingDate":"2020-05-10",value:60});
{
"acknowledged" : true,
"insertedId" : ObjectId("5ead894657bb72a10bcf0682")
}
> db.demo743.insertOne({id:1,"ShippingDate":"2020-05-11",value:75});
{
"acknowledged" : true,
"insertedId" : ObjectId("5ead895657bb72a10bcf0683")
}ここでは、id、ShippingDate(出荷日)、value(値)の3つのフィールドを持つ4件のドキュメントを登録しました。なお、id:1 のドキュメントは2件存在する点に注目してください。
登録済みドキュメントの確認
find() メソッドを使うと、コレクション内のすべてのドキュメントを表示できます。
> db.demo743.find();
上記のクエリを実行すると、次のような出力が得られます。
{ "_id" : ObjectId("5ead893a57bb72a10bcf0680"), "id" : 1, "ShippingDate" : "2020-01-21", "value" : 50 }
{ "_id" : ObjectId("5ead893c57bb72a10bcf0681"), "id" : 2, "ShippingDate" : "2020-05-10", "value" : 30 }
{ "_id" : ObjectId("5ead894657bb72a10bcf0682"), "id" : 3, "ShippingDate" : "2020-05-10", "value" : 60 }
{ "_id" : ObjectId("5ead895657bb72a10bcf0683"), "id" : 1, "ShippingDate" : "2020-05-11", "value" : 75 }コレクション全体との比較に基づくドキュメント抽出クエリ
それでは、コレクション全体との比較に基づいてドキュメント全体を抽出する集計クエリを見ていきましょう。次のパイプラインでは、複数のステージを組み合わせています。
> db.demo743.aggregate([
... {
... "$project":
... {
... "id": "$id",
... "ShippingDate": "$ShippingDate",
... "MyDoc": "$$ROOT"
... }
... },
... {
... "$sort":
... { "ShippingDate": -1
... }
... },
... {
... "$group":
... {
... "_id":{"id":"$id"},
... "Result":{"$first":"$MyDoc"}
... }
... },
... {
... $project:
... {
... "Result.ShippingDate":1, "Result.id":1, "Result.value":1, _id:0}
... }
... ])パイプラインの各ステージの役割
このクエリの仕組みをステージごとに整理すると、以下のようになります。
1. $projectステージ: $$ROOT を使ってドキュメント全体を「MyDoc」というフィールドに保持します。$$ROOTは、処理対象のドキュメントそのものを表すシステム変数です。
2. $sortステージ: ShippingDate を降順(-1)に並べ替えます。これにより、同じidの中で最も新しい出荷日のドキュメントが先頭に来ます。
3. $groupステージ: id ごとにドキュメントをグループ化し、$first 演算子で各グループの先頭(=最新)のドキュメントを「Result」として取得します。
4. 最後の$projectステージ: 出力に必要なフィールド(ShippingDate、id、value)のみを指定し、_id を除外して結果を見やすくします。
実行結果
上記の集計クエリを実行すると、次のような出力が得られます。
{ "Result" : { "id" : 3, "ShippingDate" : "2020-05-10", "value" : 60 } }
{ "Result" : { "id" : 2, "ShippingDate" : "2020-05-10", "value" : 30 } }
{ "Result" : { "id" : 1, "ShippingDate" : "2020-05-11", "value" : 75 } }結果を見ると、重複していた id:1 の2件のうち、より新しい出荷日「2020-05-11」のドキュメント(value: 75)だけが抽出されていることがわかります。このように$$ROOTを活用すれば、グループ化の際にドキュメント全体を保持しながら、条件に合致するレコードを柔軟に取得できます。
まとめ
MongoDBの集計パイプラインにおける $$ROOT は、$projectステージでドキュメント全体を一時的に保持し、$sortや$groupと組み合わせることで「各グループの最新ドキュメントを取得する」といった処理を簡単に実現できる強力な機能です。重複データの中から最新レコードだけを取り出したい場合などに、ぜひ活用してみてください。
-
MongoDBで1つのクエリを使って複数のドキュメントを一括更新する方法(bulkWrite活用ガイド)
MongoDBで1つのクエリで複数のドキュメントを更新するには?MongoDBで1回のリクエスト(1つのクエリ)で複数のドキュメントを効率的に更新したい場合は、bulkWrite()メソッドを使用します。bulkWrite()は、複数の書き込み操作(insert、update、deleteなど)をまとめてサーバーに送信できるため、個別にクエリを発行するよりもパフォーマンス面で優れています。ここでは、updateOne操作を組み合わせて、複数のドキュメントのフィールドを一度に更新する手順を具体的に解説します。1. コレクションの作成とドキュメントの挿入まず、insertOne()メソッドを使って
-
JavaのStringBuilderとStringBufferを徹底比較!実行速度から見る使い分けのポイント
StringBuilderとStringBufferの違いとは? StringBufferは、複数のスレッドが同時に同じオブジェクトへアクセスする可能性があるマルチスレッド環境でも安全に使用できるクラスです。内部のメソッドが同期化(synchronized)されているため、スレッド間でのデータ競合が発生しません。 一方、StringBuilderは、スレッドセーフなStringBufferクラスの代替としてJava 5で導入されたクラスです。synchronizedメソッドを持たないため、その分オーバーヘッドがなく、はるかに高速に動作します。単一スレッド内で文字列の連結や編集など大量の文字列操