MongoDBのaggregate()でドキュメントの共通部分(積集合)をフィールドに対して照合する方法
MongoDBでドキュメントの共通部分を照合するには
MongoDBで、あるフィールドの値ごとにグループ化したドキュメントの中から、複数の条件値をすべて含むグループ(共通部分)を抽出したい場合には、aggregate()(集計パイプライン)を利用します。本記事では、$match・$group・$all・$elemMatchを組み合わせて、特定のフィールド値の積集合を持つドキュメント群を取得する手順を解説します。
サンプルコレクションの作成
まず、insertOne()メソッドを使って、デモ用コレクション「demo393」にドキュメントを挿入します。
> db.demo393.insertOne(
... {
... Id1: "1",
... Name: "Chris",
... Id2: "100"
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e5e6dd522064be7ab44e804")
}
> db.demo393.insertOne(
... {
... Id1: "1",
... Name: "Chris",
... Id2: "101"
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e5e6dd522064be7ab44e805")
}
> db.demo393.insertOne(
... {
... Id1: "3",
... Name: "Chris",
... Id2: "100"
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e5e6dd522064be7ab44e806")
}
> db.demo393.insertOne(
... {
... Id1: "3",
... Name: "Mike",
... Id2: "101"
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5e5e6dd522064be7ab44e807")
}
登録したドキュメントの確認
find()メソッドを使うと、コレクション内のすべてのドキュメントを表示できます。
> db.demo393.find();
実行すると、次のような出力が得られます。
{ "_id" : ObjectId("5e5e6dd522064be7ab44e804"), "Id1" : "1", "Name" : "Chris", "Id2" : "100" }
{ "_id" : ObjectId("5e5e6dd522064be7ab44e805"), "Id1" : "1", "Name" : "Chris", "Id2" : "101" }
{ "_id" : ObjectId("5e5e6dd522064be7ab44e806"), "Id1" : "3", "Name" : "Chris", "Id2" : "100" }
{ "_id" : ObjectId("5e5e6dd522064be7ab44e807"), "Id1" : "3", "Name" : "Mike", "Id2" : "101" }
共通部分を照合する集計パイプライン
以下のクエリでは、まず「NameがChris」のドキュメントだけを$matchで絞り込みます。次に$groupステージでId1の値ごとにグループ化し、$$ROOTを使ってドキュメント全体をdocs配列に格納するとともに、countで各グループの件数を数えます。最後の$matchステージで、「countが1より大きい」こと、および「docs配列内にId2が100の要素と101の要素が両方存在する」ことを条件に抽出を行います。
> db.demo393.aggregate([
... { "$match": { "Name": "Chris" } },
... { "$group": {
... "_id": "$Id1",
... "docs": { "$push": "$$ROOT" },
... "count": { "$sum": 1 }
... }},
... { "$match": {
... "count": { "$gt": 1 },
... "docs": {
... "$all": [
... { "$elemMatch": { "Id2": "100" } },
... { "$elemMatch": { "Id2": "101" } }
... ]
... }
... }}
... ])
実行すると、次の出力が得られます。
{ "_id" : "1", "docs" : [ { "_id" : ObjectId("5e5e6dd522064be7ab44e804"), "Id1" : "1", "Name" : "Chris", "Id2" : "100" }, { "_id" : ObjectId("5e5e6dd522064be7ab44e805"), "Id1" : "1", "Name" : "Chris", "Id2" : "101" } ], "count" : 2 }
クエリのポイント
- $match(第1段階):Nameが「Chris」のドキュメントに事前に絞り込むことで、以降の処理対象を減らし、パフォーマンスを向上させています。
- $group:Id1の値をキーとしてグループ化し、$$ROOTで元ドキュメント全体を保持しつつ、countでグループ内の件数をカウントします。
- $allと$elemMatch:docs配列の中に「Id2が100である要素」と「Id2が101である要素」の両方が存在するかどうかを検証します。
- count > 1:同じId1のグループ内に複数件のドキュメントが存在することを保証します。
結果として、Id1が「1」のグループにはId2が「100」と「101」の両方を含むChrisのドキュメントが2件存在するため、条件を満たして出力されています。一方、Id1が「3」のグループでは、ChrisのドキュメントはId2「100」の1件しかないため、countの条件を満たせず除外される点にも注目してください。
-
$elemMatch演算子を使った配列フィールドを持つドキュメントの検索方法【MongoDB】
MongoDBで配列フィールド内の要素に基づいてドキュメントを検索したい場合、$elemMatch 演算子を使用します。$elemMatch を使うことで、配列内の同一の要素に対して複数の条件を同時に適用できるのが大きな特徴です。この記事では、実際にコレクションを作成し、配列フィールドを含むドキュメントを $elemMatch で照合する手順を解説します。1. テスト用コレクションの作成まず、配列フィールド details を持つドキュメントを挿入して、サンプルコレクションを作成しましょう。> db.demo592.insertOne( ... { ... id:1
-
MongoDBでコレクション内のドキュメントの各フィールドを数式を使って更新する方法
コレクション内のドキュメントの各フィールドを数式(計算式)で一括更新したい場合は、MongoDBの update() メソッドに $mul 演算子と全位置演算子 $[] を組み合わせて使用します。本記事では、配列内のすべての要素に対して特定のフィールドの値を乗算で更新する具体的な手順を解説します。サンプルコレクションの作成まず、insertOne() メソッドを使って、ドキュメントを含むコレクションを作成します。> db.demo749.insertOne({details:[{id:1,a:10},{id:2,a:5},{id:3,a:20}]}); { acknowledge