MongoDBで複数のサブドキュメントをフィルタリングする方法
MongoDBで複数のサブドキュメント(配列内の要素)を同時にフィルタリングするには、aggregate()メソッドを使用します。この記事では、実際のコード例を通じて、$match、$unwind、$group、$projectを組み合わせた集計パイプラインの実装方法を解説します。
サンプルコレクションの作成
まず、insertOne()メソッドを使って、複数の配列フィールド(details1、details2)を持つドキュメントを含むコレクションを作成します。
> db.demo200.insertOne(
... {
... "Id":"101",
... "details1":[
... {
... "isActive":true,
... "SubjectName":"MySQL"
... },{
... "isActive":false,
... "SubjectName":"Java"
... }
... ],
... "details2":[
... {
... "isActive":false,
... "Name":"David"
... },{
... "isActive":true,
... "Name":"Mike"
... }
... ]
... }
...);
{
"acknowledged" : true,
"insertedId" : ObjectId("5e3c374f03d395bdc21346e4")
}
登録済みドキュメントの確認
find()メソッドを使って、コレクション内のすべてのドキュメントを表示します。
> db.demo200.find();
このクエリを実行すると、次の出力が得られます。
{
"_id" : ObjectId("5e3c374f03d395bdc21346e4"), "Id" : "101", "details1" : [
{ "isActive" : true, "SubjectName" : "MySQL" },
{ "isActive" : false, "SubjectName" : "Java" } ], "details2" : [ { "isActive" : false, "Name" : "David" },
{ "isActive" : true, "Name" : "Mike" }
]
}
複数のサブドキュメントをフィルタリングするクエリ
以下が、複数のサブドキュメントをフィルタリングするための集計クエリです。
> var out= [
... {
... "$match": {
... "Id": "101",
... "details1.isActive": true,
... "details2.isActive": true
... }
... },
... { "$unwind": "$details1" },
... { "$unwind": "$details2" },
... {
... "$match": {
... "details1.isActive": true,
... "details2.isActive": true
... }
... },
... {
... "$group": {
... "_id": {
... "_id": "$_id",
... "Id": "$Id"
... },
... "details2": { "$addToSet" : "$details2" },
... "details1": { "$addToSet" : "$details1" }
... }
... },
... {
... "$project": {
... "_id": 0,
... "Id": "$_id.Id",
... "details2": 1,
... "details1": 1
... }
... }
...]
>
> db.demo200.aggregate(out)
パイプラインの各ステージの解説
このクエリは、以下のステージで構成されています。
1. $match: Idが「101」であり、かつdetails1とdetails2の両方にisActive: trueの要素が1つでも存在するドキュメントを抽出します。
2. $unwind: details1とdetails2の配列を要素ごとに展開します。これにより、各サブドキュメントを個別に扱えるようになります。
3. $match(2回目): 展開後の各要素に対してisActive: trueの条件を再適用し、条件を満たさない要素を除外します。
4. $group: 元のドキュメント単位で結果を再グループ化し、$addToSetを使ってフィルタリング済みの要素を配列として集約します。
5. $project: 出力フィールドを整形し、_idを非表示にしてId、details1、details2を返します。
実行結果
上記のクエリを実行すると、次の出力が得られます。
{ "details2" : [ { "isActive" : true, "Name" : "Mike" } ], "details1" : [ { "isActive" : true, "SubjectName" : "MySQL" } ], "Id" : "101" }
このように、isActive: falseの要素(JavaとDavid)が除外され、条件を満たすサブドキュメント(MySQLとMike)だけが抽出されていることが確認できます。
まとめ
複数の配列フィールドを同時にフィルタリングする場合、$unwindで配列を展開してから$matchで絞り込み、$groupで元の構造に戻すのが基本的なアプローチです。find()だけでは配列内の要素を個別にフィルタリングして返すことが難しいため、このようなケースではaggregate()の集計パイプラインを活用しましょう。
-
MongoDBでネストしたサブドキュメントをフィルタリングする方法(aggregateと$unwind活用)
MongoDBでは、配列の中にさらに配列(サブドキュメント)がネストしている構造を持つドキュメントから、特定の条件に合致する要素だけを抽出したいケースがあります。このような場合、aggregate()メソッドと$unwind演算子を組み合わせることで実現できます。本記事では、実際のコード例を使いながら、ネストしたサブドキュメントのフィルタリング手順を解説します。サンプルコレクションの作成まず、ネストしたサブドキュメントを含むドキュメントを挿入して、コレクションを作成しましょう。> db.demo583.insert([ ... { ... details1 : [
-
MongoDBのaggregateで$groupを使って複数の集計結果を一度に取得する方法
MongoDBでは、$facetと$groupを組み合わせることで、1回のaggregateクエリで複数の集計結果を同時に取得できます。この記事では、実際のコード例を通じてその方法を解説します。サンプルコレクションの作成まず、ドキュメントを含むコレクションを作成しましょう。以下のようにinsertOne()メソッドを使ってデータを挿入します。> db.demo765.insertOne( ... { ... Name:John, ... Category:ComputerScience, ... SubjectName:MongoDB,