SQL GROUP BYとHAVINGをMongoDBの$group後の$matchに変換する
SQL HAVING句が集計後のフィルタリングのために集計パイプラインの$group後に配置される$matchステージに変換される方法を学びます。
Advanced
詳細な説明
HAVINGから$group後の$matchへ
SQLのHAVING句は集計後にグループをフィルタリングします。行を事前にフィルタリングするWHEREとは異なります。MongoDBの集計パイプラインでは、これは$groupステージの後に配置される$matchステージに変換されます。
SQLの例
SELECT category, COUNT(*) AS total
FROM products
GROUP BY category
HAVING COUNT(*) >= 5
生成されるMongoDBクエリ
db.products.aggregate([
{
$group: {
_id: "$category",
total: { $sum: 1 },
category: { $first: "$category" }
}
},
{ $match: { total: { $gte: 5 } } }
])
パイプラインの順序が重要
MongoDBの集計パイプラインでのステージの順序は重要です:
- $match(WHERE)— グループ化前にドキュメントをフィルタリング
- $group — 集計を実行
- $match(HAVING)— 集計後にグループをフィルタリング
- $sort — 結果をソート
- $limit — 出力を制限
WHEREとHAVINGの組み合わせ
SELECT category, AVG(price) AS avg_price
FROM products
WHERE status = 'active'
GROUP BY category
HAVING AVG(price) > 25
db.products.aggregate([
{ $match: { status: "active" } },
{
$group: {
_id: "$category",
avg_price: { $avg: "$price" },
category: { $first: "$category" }
}
},
{ $match: { avg_price: { $gt: 25 } } }
])
異なる位置に2つの$matchステージがあることに注目してください — 最初のものはドキュメントをフィルタリング(WHERE)し、2番目のものはグループをフィルタリング(HAVING)します。
集計フィールドの参照
HAVINGの$matchステージでは、元のドキュメントフィールドではなく、$groupステージで定義されたフィールド名(totalやavg_priceなど)を参照します。これはSQLでHAVINGがエイリアス名や集計式を参照するのと類似しています。
パフォーマンスの最適化
可能な場合は常に$groupの前にWHERE相当の$matchステージを含めてください。これにより、グループ化が必要なドキュメントの数が削減され、大規模なコレクションでのパフォーマンスが大幅に向上します。
ユースケース
大量カテゴリの特定、注文数によるトップ顧客、予算を超過する部門などのビジネスインテリジェンスクエリは、集計後のフィルタリングにHAVINGを使用します。このパターンはサマリーレポートやアラートシステムの構築に不可欠です。