Docs Menu

集計によるデータの変換

このガイドでは、 MongoDB PHPライブラリを使用して集計操作を実行する方法を学習できます。

集計操作により MongoDB コレクション内のデータが処理され、計算結果が返されます。 クエリ API の一部である MongoDB 集計フレームワークは、データ処理パイプラインの概念をモデル化したものです。 ドキュメントは 1 つ以上の ステージを含むパイプラインに投入され、そこで集計結果に変換されます。

集計操作は自動車工場に似ています。工場内の組立ラインには、ドリルや溶接機のような、特定の作業をするための専用工具を備えた組立ステーションがあります。未加工のパーツが工場に搬入され、組立ラインで完成品に加工、組み立てられます。

集計パイプラインは組み立てライン、集計ステージは組み立てステーション、演算子式は専用ツールです。

検索操作を使用して、次のアクションを実行できます。

  • どのドキュメントを返すかを選ぶ

  • どのフィールドを返すかを選ぶ

  • 結果を並べ替える

集計操作を使用して、次のアクションを実行できます。

  • 検索操作の実行

  • フィールドの名前を変更する

  • フィールドを計算する

  • データを要約する

  • 値をグループ化する

集計操作を実行する際には、次の制限を考慮してください。

  • 返されたドキュメントは、 BSONドキュメントサイズの制限である16メガバイトに違反することはできません。

  • パイプライン ステージには、デフォルトで100メガバイトのメモリ制限があります。 この制限を超えるには、 allowDiskUseオプションをtrueに設定するオプション配列を作成し、その配列をMongoDB\Collection::aggregate()メソッドに渡します。

    重要

    $graphLookup の例外

    $graphLookupステージは100メガバイトという厳格なメモリ制限があり、 allowDiskUseオプションを無視します。

PHPライブラリは、集計パイプラインを作成するための次の API を提供します。

  • 配列API :集計ステージを指定する配列を渡して集計パイプラインを作成します。

  • 集計ビルダー : ファクトリー メソッドを使用して集計パイプラインを作成し、アプリケーションの型安全性とデバッグ可能性を高めます。

以下のセクションでは、各APIの説明と、集計パイプラインの作成例を示します。

集計を実行するには、次のコードに示すように、パイプラインステージを含む配列をBSONドキュメントとして MongoDB\Collection::aggregate() メソッドに渡します。

$pipeline = [
['<stage>' => <parameters>],
['<stage>' => <parameters>],
// ...
];
$cursor = $collection->aggregate($pipeline);

このセクションの例では、 Atlas サンプル データセットsample_restaurantsデータベースのrestaurantsコレクションを使用します。 MongoDB Atlas クラスターを無料で作成して、サンプル データセットをロードする方法については、 「 Atlas を使い始める 」ガイドを参照してください。

次のコード例では、ニューヨークの各地区のケーキの数のカウントを生成します。 そのために、次のステージを含む集計パイプラインを使用します。

  1. $matchステージcuisineフィールドに値'Bakery'が含まれるドキュメントをフィルタリングします。

  2. $groupステージでは、一致するドキュメントをboroughフィールドでグループ化し、個別の 値ごとにドキュメントの数を蓄積します

$pipeline = [
['$match' => ['cuisine' => 'Bakery']],
['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]],
];
$cursor = $collection->aggregate($pipeline);
foreach ($cursor as $doc) {
echo json_encode($doc), PHP_EOL;
}
{"_id":"Brooklyn","count":173}
{"_id":"Queens","count":204}
{"_id":"Bronx","count":71}
{"_id":"Staten Island","count":20}
{"_id":"Missing","count":2}
{"_id":"Manhattan","count":221}

MongoDBが操作を実行する方法に関する情報を表示するには、 MongoDBクエリ プランナーにそれを説明するように指示できます。 MongoDBが操作を説明すると、実行プランとパフォーマンス統計が返されます。 実行プランは、 MongoDBが操作を完了できる潜在的な方法です。 MongoDBに操作を説明するように指示すると、 MongoDBが実行したプランと拒否された実行プランの両方が返されます。

集計操作を説明するには、 MongoDB\Operation\Aggregateオブジェクトを作成し、データベース、コレクション、パイプラインステージをパラメーターとして渡します。 次に、 MongoDB\Operation\AggregateオブジェクトをMongoDB\Collection::explain()メソッドに渡します。

次の例では、 MongoDB に前のセクションの集計操作を説明するように指示します。

$pipeline = [
['$match' => ['cuisine' => 'Bakery']],
['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]],
];
$aggregate = new MongoDB\Operation\Aggregate(
$collection->getDatabaseName(),
$collection->getCollectionName(),
$pipeline
);
$result = $collection->explain($aggregate);
echo json_encode($result), PHP_EOL;
{"explainVersion":"2","queryPlanner":{"namespace":"sample_restaurants.restaurants",
"indexFilterSet":false,"parsedQuery":{"cuisine":{"$eq":"Bakery"}},"queryHash":"865F14C3",
"planCacheKey":"D56D6F10","optimizedPipeline":true,"maxIndexedOrSolutionsReached":false,
"maxIndexedAndSolutionsReached":false,"maxScansToExplodeReached":false,"winningPlan":{
... }

集計ビルダ を使用して集計パイプラインを作成するには、次のアクションを実行します。

  1. パイプラインステージを保存するには、MongoDB\Builder\Pipelineインスタンスを作成します。

  2. 各ステージについて、目的の集計ステージと同じ名前を共有する Stage からファクトリー メソッドを呼び出します。例、$unwind ステージを作成するには、Stage::unwind() メソッドを呼び出します。

  3. Stage メソッドの本体内で、QueryExpressionAccumulator などの他のビルダ クラスのメソッドを使用して集計仕様をExpress。

次のコードは、集計パイプラインを構築するためのテンプレートを示しています。

$pipeline = new Pipeline(
Stage::<factory method>(
<stage specification>
),
Stage::<factory method>(
<stage specification>
),
// ...
);
$cursor = $collection->aggregate($pipeline);

このセクションの例は、MongoDB Serverマニュアルを使用しています。各例には、データベースに挿入して集計操作をテストできるサンプルデータへのリンクが記載されています。

Tip

ビルダを用いた操作

ビルダを使用すると、検索や更新操作などの非集計操作をサポートできます。詳しくは、「 ビルダを使用した 操作のガイド 」をご覧ください。

この例では、サーバー マニュアルの $group ステージ参照の 「カウント、合計、平均の計算」セクションに記載されているサンプルデータを使用します。

次のコード例では、2014 年 の各日の合計売上額、平均売上数量、売上件数を計算します。そのために、次のステージを含む集計パイプラインを使用します。

  1. $match ステージ: 年が 2014 である dateフィールドを含むドキュメントをフィルタリングします

  2. ドキュメントを日付別にグループ化し、各グループの合計売上額、平均売上数量、売上件数を計算する $group ステージ

  3. $sort ステージ: 結果を各グループの合計売上額の降順でソートします

$pipeline = new MongoDB\Builder\Pipeline(
MongoDB\Builder\Stage::match(
date: [
MongoDB\Builder\Query::gte(new MongoDB\BSON\UTCDateTime(new DateTimeImmutable('2014-01-01'))),
MongoDB\Builder\Query::lt(new MongoDB\BSON\UTCDateTime(new DateTimeImmutable('2015-01-01'))),
],
),
MongoDB\Builder\Stage::group(
_id: MongoDB\Builder\Expression::dateToString(MongoDB\Builder\Expression::dateFieldPath('date'), '%Y-%m-%d'),
totalSaleAmount: MongoDB\Builder\Accumulator::sum(
MongoDB\Builder\Expression::multiply(
MongoDB\Builder\Expression::numberFieldPath('price'),
MongoDB\Builder\Expression::numberFieldPath('quantity'),
),
),
averageQuantity: MongoDB\Builder\Accumulator::avg(
MongoDB\Builder\Expression::numberFieldPath('quantity'),
),
count: MongoDB\Builder\Accumulator::sum(1),
),
MongoDB\Builder\Stage::sort(
totalSaleAmount: MongoDB\Builder\Type\Sort::Desc,
),
);
$cursor = $collection->aggregate($pipeline);
foreach ($cursor as $doc) {
echo json_encode($doc), PHP_EOL;
}
{"_id":"2014-04-04","totalSaleAmount":{"$numberDecimal":"200"},"averageQuantity":15,"count":2}
{"_id":"2014-03-15","totalSaleAmount":{"$numberDecimal":"50"},"averageQuantity":10,"count":1}
{"_id":"2014-03-01","totalSaleAmount":{"$numberDecimal":"40"},"averageQuantity":1.5,"count":2}

この例では、サーバー マニュアルの $unwind ステージ参照の 「埋め込み配列の展開」セクションに記載されているサンプルデータを使用します。

次のコード例では、販売された商品をタグごとにグループ化し、タグごとに合計販売額を計算します。そのために、次のステージを含む集計パイプラインを使用します。

  1. $unwind ステージ: items 配列の要素ごとに個別のドキュメントを出力

  2. $unwind ステージ: items.tags 配列の各要素に対して個別のドキュメントを出力します

  3. $group ステージ: ドキュメントをタグの値でグループ化し、各タグを持つアイテムの合計売上額を計算します。

$pipeline = new MongoDB\Builder\Pipeline(
MongoDB\Builder\Stage::unwind(MongoDB\Builder\Expression::arrayFieldPath('items')),
MongoDB\Builder\Stage::unwind(MongoDB\Builder\Expression::arrayFieldPath('items.tags')),
MongoDB\Builder\Stage::group(
_id: MongoDB\Builder\Expression::fieldPath('items.tags'),
totalSalesAmount: MongoDB\Builder\Accumulator::sum(
MongoDB\Builder\Expression::multiply(
MongoDB\Builder\Expression::numberFieldPath('items.price'),
MongoDB\Builder\Expression::numberFieldPath('items.quantity'),
),
),
),
);
$cursor = $collection->aggregate($pipeline);
foreach ($cursor as $doc) {
echo json_encode($doc), PHP_EOL;
}
{"_id":"office","totalSalesAmount":{"$numberDecimal":"1019.60"}}
{"_id":"school","totalSalesAmount":{"$numberDecimal":"104.85"}}
{"_id":"stationary","totalSalesAmount":{"$numberDecimal":"264.45"}}
{"_id":"electronics","totalSalesAmount":{"$numberDecimal":"800.00"}}
{"_id":"writing","totalSalesAmount":{"$numberDecimal":"60.00"}}

この例では、サーバー マニュアルの $lookup ステージ参照の 「$lookup を使用して単一の等価結合を実行する」 セクションに記載されているサンプルデータを使用します。

次のコード例では、ordersコレクションの itemフィールドと inventoryコレクションの skuフィールドを使用して、ordersコレクションのドキュメントと inventoryコレクションのドキュメントを結合します。

そのために、この例では、データを取得するコレクションとローカル フィールド名と外部フィールド名を指定する$lookupステージを含む集計パイプラインを使用します。

$pipeline = new MongoDB\Builder\Pipeline(
MongoDB\Builder\Stage::lookup(
from: 'inventory',
localField: 'item',
foreignField: 'sku',
as: 'inventory_docs',
),
);
/* Performs the aggregation on the orders collection */
$cursor = $collection->aggregate($pipeline);
foreach ($cursor as $doc) {
echo json_encode($doc), PHP_EOL;
}
{"_id":1,"item":"almonds","price":12,"quantity":2,"inventory_docs":[{"_id":1,"sku":"almonds","description":"product 1","instock":120}]}
{"_id":2,"item":"pecans","price":20,"quantity":1,"inventory_docs":[{"_id":4,"sku":"pecans","description":"product 4","instock":70}]}
{"_id":3,"inventory_docs":[{"_id":5,"sku":null,"description":"Incomplete"},{"_id":6}]}

MongoDB PHPライブラリを使用して複雑な集計パイプラインを作成するチュートリアルについては、 MongoDB Developer Center の「 MongoDB Ops PHPとMongoDBを使用した複雑な集計パイプライン 」を参照してください。

集計ビルダを使用して構築された集計パイプラインのその他の例については、Github のPHPライブラリソースコードのステージクラステスト スイート を参照してください。

このガイドで説明されているトピックについて詳しくは、 MongoDB Serverマニュアルの次のページ を参照してください。

Atlas Search 機能を使用して、全文検索を実行できます。詳しくは、「 Atlas Searchガイド 」を参照してください。

Atlas ベクトル検索機能を使用して、ベクトル埋め込みに対して類似性検索を実行できます。 詳細については、「 Atlas ベクトル検索ガイド 」を参照してください。

このガイドで説明されているメソッドの詳細については、次のAPIドキュメントを参照してください。