MongoDBの集計パイプラインで複数フィールドをカウントする方法($facet活用)
MongoDBで複数のフィールドごとにドキュメントをカウントしたい場合、$facet演算子を使うのが効果的です。$facetは、同じ入力ドキュメント群に対して、単一のステージ内で複数の集計パイプラインを同時に処理できる強力な機能です。
この記事では、実際にコレクションを作成し、$facetを組み合わせた集計クエリで複数フィールドの値をカウントする手順を解説します。
1. サンプルコレクションの作成
まず、insertOne()メソッドを使ってサンプルドキュメントを挿入します。各ドキュメントにはdetails1・details2・details3という3つのネストされたフィールドを持たせます。
> db.demo721.insertOne(
... {
... "details1": {
... "id": 101
... },
... "details2": {
... "id": 101
... },
... "details3": {
... "id": 101
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5eaaebdd43417811278f5887")
}続けて2件目のドキュメントも挿入します。
> db.demo721.insertOne(
... {
... "details1": {
... "id": 101
... },
... "details2": {
... "id": 102
... },
... "details3": {
... "id": 102
... }
... }
... );
{
"acknowledged" : true,
"insertedId" : ObjectId("5eaaebe943417811278f5888")
}2. 登録データの確認
find()メソッドを使って、コレクション内のすべてのドキュメントを表示して確認しましょう。
> db.demo721.find();
実行すると、以下のような出力が得られます。
{ "_id" : ObjectId("5eaaebdd43417811278f5887"), "details1" : { "id" : 101 }, "details2" : { "id" : 101 }, "details3" : { "id" : 101 } }
{ "_id" : ObjectId("5eaaebe943417811278f5888"), "details1" : { "id" : 101 }, "details2" : { "id" : 102 }, "details3" : { "id" : 102 } }3. $facetを使った複数フィールドのカウントクエリ
ここからが本題です。以下のクエリでは、$facetを使って2つのサブパイプライン(idsとd)を並行処理しています。
- idsパイプライン: $groupと$addToSetで各フィールドのユニークなID一覧を収集し、$setUnionで統合したリストを作成します。
- dパイプライン: 各ドキュメントからdetails1〜3のIDだけを抽出した配列を作成します。
その後、$unwindで配列を展開し、$groupと$cond(条件付き加算)を組み合わせることで、各IDがdetails1・details2・details3それぞれに出現した回数をカウントしています。
> db.demo721.aggregate([
... {$facet:{
... ids:[
... {$group:{ _id:null,
... d3:{$addToSet: "$details3.id"},
... d2:{$addToSet:"$details2.id"},
... d1:{$addToSet:"$details1.id"}}},
... {$project:{ _id:0,
... listofall:{$setUnion:["$d1","$d2","$d3"]}}}],
... d:[{$project:{ _id:0,
... a1:"$details1.id",
... a2:"$details2.id",
... a3:"$details3.id"}}]}},
... {$unwind:"$d"},
... {$unwind:"$ids"},
... {$unwind:"$ids.listofall"},
... {$group:{ _id:"$ids.listofall",
... details1id:{$sum:{$cond:[{$eq:["$d.a1","$ids.listofall"]},1,0]}},
... details2id:{$sum:{$cond:[{$eq:["$d.a2","$ids.listofall"]},1,0]}},
... details3id:{$sum:{$cond:[{$eq:["$d.a3","$ids.listofall"]},1,0]}}}}])4. 実行結果
上記の集計クエリを実行すると、以下のような結果が出力されます。
{ "_id" : 102, "details1id" : 0, "details2id" : 1, "details3id" : 1 }
{ "_id" : 101, "details1id" : 2, "details2id" : 1, "details3id" : 1 }結果の読み方
この出力は次のことを意味しています。
- ID「101」の場合: details1に2回、details2に1回、details3に1回出現しています。
- ID「102」の場合: details1には出現せず(0回)、details2とdetails3にそれぞれ1回ずつ出現しています。
$facetを活用すれば、1回のaggregate()呼び出しで複数の観点からの集計を効率的に実行できるため、大規模なコレクションに対する分析処理でもパフォーマンス面で有利です。複数フィールドにまたがる値の出現回数を調べたいときは、ぜひこのパターンを参考にしてください。
-
MongoDBの集約パイプラインでフィールドを結合・マージしてカウントする方法
MongoDBでフィールドを結合またはマージした上で件数を数えたい場合、$group演算子を$sumや$sortと組み合わせて使用します。この記事では、実際にコレクションを作成し、集約パイプラインを使って科目ごとのドキュメント数を集計する手順を解説します。サンプルコレクションの作成まず、insertOne()メソッドを使ってドキュメントを作成します。 db.demo647.insertOne({Subject:MongoDB}); { acknowledged : true, insertedId : ObjectId(5e9c86c16c954c74be91e6f4) }登録した
-
MySQLで複数の列に対して複数のCOUNTを取得する方法
はじめにMySQLでは、COUNT()を複数使わなくても、集計関数SUM()とIF()を組み合わせることで、異なる条件に基づく複数のカウントを1つのクエリで同時に取得できます。この記事では、複数の列を対象に複数の件数を集計する具体的な手順を解説します。サンプルテーブルの作成まず、以下のコマンドでテーブルを作成します。mysql> create table DemoTable ( FirstName varchar(100), LastName varchar(100) ); Query OK, 0 rows affected (2.80 sec)レコードの挿入次に、INS