MongoDB Academy · レッスン

パイプラインの概念:ステージ、演算子、式

データがパイプラインの各ステージを通過する仕組みを理解し、ステージ演算子と式演算子を区別します。

レッスン 1/413 ステップ

「パイプラインの概念:ステージ、演算子、式」はCoddyKit上の無料MongoDB Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはMongoDB Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 MongoDB Academyコースには全4レッスンが含まれています。

集計パイプラインとは

集計パイプラインは、MongoDBのサーバーサイドデータ変換エンジンです。生のドキュメントを取得してアプリケーションコードで処理する代わりに、データストリームを段階的に変換するステージの順序を定義します。フィルタリング、形状変更、グループ化、計算、並べ替えをすべてデータベースエンジン内で実行できます。これにより、負荷の高い計算をデータの近くで行い、ネットワーク経由で送信するデータ量を大幅に減らせます。

// A simple aggregation pipeline
db.orders.aggregate([
  { $match: { status: 'completed' } },   // stage 1: filter
  { $group: { _id: '$userId', total: { $sum: '$amount' } } },  // stage 2: group
  { $sort: { total: -1 } },             // stage 3: sort
  { $limit: 10 }                        // stage 4: take top 10
]);

ドキュメントがステージを通過する仕組み

パイプラインをベルトコンベアのように考えてみましょう。各ドキュメントはステージ1に入り、変換(または除外)された後、結果がステージ2、ステージ3へと順に流れていきます。各ステージで、ドキュメントの集合は縮小(フィルタリング)したり、拡大(unwind)したり、計算された集計結果に完全に置き換えられたりします。フィルター条件を満たさないドキュメントはパイプラインから除外され、後続のステージに到達することはありません。

// Data flow visualization:
// Input: 10,000 orders
// Stage 1 ($match: status='completed'):  8,000 docs
// Stage 2 ($group by userId):            1,200 docs (one per user)
// Stage 3 ($sort by total DESC):         1,200 docs (reordered)
// Stage 4 ($limit 10):                      10 docs
// Output to client: 10 docs

ステージ演算子と式演算子

集計フレームワークでは、2種類の演算子を区別します。ステージ演算子($が先頭に付く)は、$match、$group、$projectのようにパイプラインステージの処理内容を定義します。一方、式演算子(こちらも$が先頭に付く)は、$sum、$avg、$concatのようにステージ内で値を計算します。ステージが処理の構成要素であり、式はその内部で行う計算です。

db.sales.aggregate([
  // $group is a STAGE operator
  { $group: {
    _id: '$region',
    // $sum and $avg are EXPRESSION operators (accumulators here)
    totalRevenue: { $sum: '$amount' },
    avgOrder: { $avg: '$amount' },
    // $concat is an expression operator
    label: { $concat: ['Region: ', '$region'] }
  }}
]);

$記号を使用したフィールド参照

集計式の中で$が先頭に付いた文字列はフィールド参照であり、現在のドキュメントにあるそのフィールドの値を参照します。接頭辞がない文字列はリテラル値として扱われます。この違いは非常に重要です。'$price'は「priceフィールドの値」を意味しますが、'price'はリテラル文字列「price」を意味します。

db.products.aggregate([
  { $project: {
    name: 1,
    // '$price' references the 'price' field value
    discountedPrice: { $multiply: ['$price', 0.9] },
    // 'price' without $ is a literal string
    label: 'price',  // all docs get the string 'price', not the field value
    // $$ROOT is a special variable for the whole document
    original: '$$ROOT'
  }}
]);

システム変数: $$ROOT、$$NOW、$$CURRENT

集計パイプラインには、$$が先頭に付いたシステム変数が用意されており、特殊な値にアクセスできます。$$ROOTは現在のドキュメント全体を参照し、$$NOWは現在の日時を表します($projectで計算フィールドを作成する場合に便利です)。$$CURRENTは現在のドキュメントのフィールドパスコンテキストを表し、$$REMOVEは値として割り当てると条件付きでフィールドを削除します。

db.orders.aggregate([
  { $project: {
    _id: 1,
    orderDate: 1,
    daysOld: {
      $divide: [
        { $subtract: ['$$NOW', '$orderDate'] },  // $$NOW = current time
        1000 * 60 * 60 * 24  // convert ms to days
      ]
    },
    // Conditionally remove a field:
    sensitiveField: { $cond: { if: '$isAdmin', then: '$secret', else: '$$REMOVE' } }
  }}
]);

主要なパイプラインステージの概要

MongoDBには数十種類のパイプラインステージがあります。特に重要なのは、$match(ドキュメントをフィルタリング)、$project(フィールドの形状変更・計算)、$group(キーごとの集計)、$sort(結果の並べ替え)、$limitと$skip(ページネーション)、$lookup(別のコレクションとの結合)、$unwind(配列のフラット化)です。これらを使いこなせば、ほぼあらゆる分析クエリを表現できます。

// Quick reference of the most-used stages:
// $match   - { $match: { field: condition } }
// $project - { $project: { keep: 1, drop: 0, computed: expr } }
// $group   - { $group: { _id: '$field', agg: { $sum: '$val' } } }
// $sort    - { $sort: { field: 1 or -1 } }
// $limit   - { $limit: N }
// $skip    - { $skip: N }
// $lookup  - { $lookup: { from, localField, foreignField, as } }
// $unwind  - { $unwind: '$arrayField' }

パイプラインの最適化: ステージの順序が重要

MongoDBのクエリオプティマイザーは、効率化のために一部のパイプラインステージを自動的に並べ替えます。たとえば可能な場合は、$matchを$sortや$groupより前に移動します。ただし、自分で$matchを常にできるだけ早い段階に配置してください$matchが最初のステージであれば、MongoDBはインデックスを使用できます。

// BAD: expensive group before filter
db.orders.aggregate([
  { $group: { _id: '$userId', total: { $sum: '$amount' } } },
  { $match: { total: { $gt: 1000 } } }  // too late to use index
]);

// GOOD: filter first, then group
db.orders.aggregate([
  { $match: { status: 'completed', createdAt: { $gte: thisYear } } },
  { $group: { _id: '$userId', total: { $sum: '$amount' } } },
  { $match: { total: { $gt: 1000 } } }
]);

算術式演算子

算術式を使うと、ステージ内の既存のフィールドから新しい値を計算できます。特によく使われるものは、$add、$subtract、$multiply、$divide、$mod、$absです。これらの演算子は、フィールド参照、リテラル、または他の式の結果に対して使用できるため、これまでアプリケーション側で処理する必要があった複雑な計算も実行できます。

db.invoices.aggregate([
  { $project: {
    subtotal: '$subtotal',
    taxAmount: { $multiply: ['$subtotal', 0.08] },  // 8% tax
    total: { $add: ['$subtotal', { $multiply: ['$subtotal', 0.08] }] },
    discount: { $subtract: ['$listPrice', '$salePrice'] },
    margin: { $divide: [{ $subtract: ['$price', '$cost'] }, '$price'] }
  }}
]);

条件式: $cond と $ifNull

条件式を使うと、集計ステージ内でif/else ロジックを記述できます。$condはブール式を評価し、2つの値のいずれかを返します(3項演算子に相当します)。$ifNullは、フィールドがnullまたは存在しない場合に代替値を返します。これらは、任意フィールドを処理したり、保存されたデータを変更せずに派生カテゴリを計算したりするために不可欠です。

db.products.aggregate([
  { $project: {
    name: 1,
    price: 1,
    // Ternary: label products as budget or premium
    tier: {
      $cond: {
        if: { $lt: ['$price', 100] },
        then: 'budget',
        else: 'premium'
      }
    },
    // Fallback for missing description
    description: { $ifNull: ['$description', 'No description available'] }
  }}
]);

文字列式演算子

文字列演算子を使うと、パイプライン内でテキストフィールドを操作できます。$concatは文字列を連結し、$toUpper/$toLowerは大文字と小文字を変換し、$trim/$ltrim/$rtrimは空白を削除し、$substrは部分文字列を抽出し、$splitは区切り文字で分割します。これらは、保存されたドキュメントを更新せずに、集計中にデータを正規化する場合に役立ちます。

db.users.aggregate([
  { $project: {
    // Combine first and last name
    fullName: { $concat: ['$firstName', ' ', '$lastName'] },
    // Normalise email to lowercase
    emailNorm: { $toLower: '$email' },
    // Extract domain from email
    domain: {
      $arrayElemAt: [{ $split: ['$email', '@'] }, 1]
    }
  }}
]);

日付式演算子

日付演算子は、グループ化や計算のために日付フィールドから各要素を抽出します。$year、$month、$dayOfMonth、$hour、$minute、$dayOfWeek、$dateToStringなどがあります。これらは、「月ごとの注文総数」や「曜日ごとの平均売上」のような時系列分析に不可欠です。

// Group orders by year and month
db.orders.aggregate([
  { $group: {
    _id: {
      year: { $year: '$createdAt' },
      month: { $month: '$createdAt' }
    },
    count: { $sum: 1 },
    revenue: { $sum: '$amount' }
  }},
  { $sort: { '_id.year': 1, '_id.month': 1 } }
]);

理解度チェック

このレッスンで学んだ集計パイプラインの概念について、理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、パイプラインステージがドキュメントのストリームを順番に変換すること、ステージ演算子がステージの処理内容を定義する一方で、式演算子がステージ内の値を計算すること、そして$がフィールド参照の前置詞、$$がシステム変数の前置詞であることを学びました。次は、フィルターと形状変更の中心となる$matchと$projectに焦点を当てます。

無料で開始

AI チューターと学ぶ JavaScript — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
30
レッスン
120

よくある質問

「パイプラインの概念:ステージ、演算子、式」レッスンは無料ですか?

はい。「パイプラインの概念:ステージ、演算子、式」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、MongoDB Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 MongoDB Academyコースには全4レッスンが含まれています。

「パイプラインの概念:ステージ、演算子、式」で何を学びますか?

データがパイプラインの各ステージを通過する仕組みを理解し、ステージ演算子と式演算子を区別します。 ブラウザで直接実行するハンズオンコードでMongoDB Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

MongoDB Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのMongoDB Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「パイプラインの概念:ステージ、演算子、式」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このMongoDB Academyレッスンでコードを書いて実行できますか?

はい。すべてのMongoDB Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. パイプラインの概念:ステージ、演算子、式
  2. $matchと$project:フィルターと形状変更
  3. $group:集約と合計値の計算
  4. パイプラインでの$sort、$limit、$skip
← MongoDB Academyに戻る