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の集計パイプラインでのステージの順序は重要です:

  1. $match(WHERE)— グループ化前にドキュメントをフィルタリング
  2. $group — 集計を実行
  3. $match(HAVING)— 集計後にグループをフィルタリング
  4. $sort — 結果をソート
  5. $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ステージで定義されたフィールド名(totalavg_priceなど)を参照します。これはSQLでHAVINGがエイリアス名や集計式を参照するのと類似しています。

パフォーマンスの最適化

可能な場合は常に$groupの前にWHERE相当の$matchステージを含めてください。これにより、グループ化が必要なドキュメントの数が削減され、大規模なコレクションでのパフォーマンスが大幅に向上します。

ユースケース

大量カテゴリの特定、注文数によるトップ顧客、予算を超過する部門などのビジネスインテリジェンスクエリは、集計後のフィルタリングにHAVINGを使用します。このパターンはサマリーレポートやアラートシステムの構築に不可欠です。

試してみる — SQL to MongoDB Query

フルツールを開く