Docs Menu

集計ビルダー

このガイドでは、Lambda 統合集計ビルダを使用して集計を実行し、パイプラインを構築する方法を学習できます。 集計ビルダーを使用すると、タイプセーフな構文を使用して MongoDB集計パイプラインを構築できます。

集計パイプラインとは、MongoDB database のデータに対して変換と計算を順番に実行し、その結果を新しいドキュメントまたはドキュメントのセットとして出力するデータ処理パイプラインです。

集計パイプラインは、集計ステージで構成されています。 集計ステージでは、演算子を使用して入力データを処理し、次のステージが入力として使用するデータを生成します。

Lambda MongoDB 集計ビルダを使用すると、集計ステージと集計パイプラインをビルドできます。 次のセクションでは、集計ビルダーを使用して集計パイプラインのステージを作成する方法の例を示します。

Tip

集計ビルダー機能は Lambda MongoDB バージョン4.3以降でのみ使用できます。 集計ビルダを使用せずに集計を実行する方法の詳細については、クエリ ビルダ ガイドの「集計」を参照してください。

集計パイプラインを開始するには、Model::aggregate() メソッドを呼び出します。次に、集計ステージ メソッドを集計、 ステージに必要なパラメーターを指定します。例、sort() 演算子メソッドを呼び出して $sort ステージを構築できます。

集計ビルダーには、集計ステージを構築するためにインポートできる次の名前空間が含まれています。

  • MongoDB\Builder\Accumulator

  • MongoDB\Builder\Expression

  • MongoDB\Builder\Query

  • MongoDB\Builder\Type

このセクションでは、一般的な集計ステージの使用方法を示す次の例を紹介します。

MongoDB 集計演算子の詳細については、サーバー マニュアルの「集計ステージ」を参照してください。

次の例では、 Userモデルで表されるコレクションに対して集計パイプラインを実行します。 次のinsert()メソッドを実行してサンプル データを追加できます。

User::insert([
['name' => 'Alda Gröndal', 'occupation' => 'engineer', 'birthday' => new UTCDateTime(new DateTimeImmutable('2002-01-01'))],
['name' => 'Francois Soma', 'occupation' => 'engineer', 'birthday' => new UTCDateTime(new DateTimeImmutable('1998-02-02'))],
['name' => 'Janet Doe', 'occupation' => 'designer', 'birthday' => new UTCDateTime(new DateTimeImmutable('1987-03-03'))],
['name' => 'Eliud Nkosana', 'occupation' => 'engineer', 'birthday' => new UTCDateTime(new DateTimeImmutable('1984-04-04'))],
['name' => 'Bran Steafan', 'occupation' => 'engineer', 'birthday' => new UTCDateTime(new DateTimeImmutable('1998-05-05'))],
['name' => 'Ellis Lee', 'occupation' => 'designer', 'birthday' => new UTCDateTime(new DateTimeImmutable('1996-06-06'))],
]);

クエリフィルターを指定するには、 match()メソッドを集計パイプラインにチェーンできます。 このステージを省略すると、 aggregate()メソッドは次の ステージのモデルの コレクション内のすべてのドキュメントを出力します。

この集計ステージは、利用可能なインデックスを使用してデータを取得し、後続のステージで処理されるデータ量を減らすために、多くの場合最初に配置されます。

Tip

match()メソッドを省略すると、集計パイプラインは他の集計ステージの前のモデルに対応するコレクション内のすべてのドキュメントと一致します。

この例では、 MongoDB\Builder\Queryビルダを使用して、一致集計ステージのクエリフィルターを構築します。 一致ステージには、次の条件が含まれます。

  • Query::or()関数を使用して、クエリフィルターのいずれかに一致する結果を返します

  • occupation関数と 関数を使用して、値が である フィールドを含むドキュメントと一致させます"designer"Query::query()Query::eq()

  • name関数と"Eliud Nkosana" Query::query()関数を使用して、 の値を持つ フィールドを含むドキュメントと一致させますQuery::eq()

コードの実行によって返されたドキュメントを確認するには、[ VIEW OUTPUT ] ボタンをクリックします。

$pipeline = User::aggregate()
->match(Query::or(
Query::query(occupation: Query::eq('designer')),
Query::query(name: Query::eq('Eliud Nkosana')),
));
$result = $pipeline->get();
[
{
"_id": ...,
"name": "Janet Doe",
"occupation": "designer",
"birthday": {
"$date": {
"$numberLong": "541728000000"
}
}
},
{
"_id": ...,
"name": "Eliud Nkosana",
"occupation": "engineer",
"birthday": {
"$date": {
"$numberLong": "449884800000"
}
}
},
{
"_id": ...,
"name": "Ellis Lee",
"occupation": "designer",
"birthday": {
"$date": {
"$numberLong": "834019200000"
}
}
}
]

Tip

Query::or()関数は、 $or MongoDB クエリ演算子に対応します。 この演算子の詳細については、サーバー マニュアルの$orを参照してください。

group()メソッドを集計パイプラインにチェーンして、計算を実行し、一般的なフィールド値でグループ化してデータの構造を変更できます。

この集計ステージは、後続のステージで処理されるデータを減らすために、多くの場合、一致ステージの直後に配置されます。

この例では、 MongoDB\Builder\Expressionビルダを使用して、グループ集計ステージでグループキーを定義します。 グループ ステージでは、次のグループ化動作を指定します。

  • _idフィールドで表されるグループ キーの値を、 Expressionビルダで定義されたフィールド値に設定します

  • Expression::fieldPath()関数を呼び出して、 occupationフィールドのドキュメント値を参照します

コードの実行によって返されたドキュメントを確認するには、[ VIEW OUTPUT ] ボタンをクリックします。

$pipeline = User::aggregate()
->group(_id: Expression::fieldPath('occupation'));
$result = $pipeline->get();
[
{ "_id": "engineer" },
{ "_id": "designer" }
]

Tip

このサンプル ステージでは、 distinct()クエリ ビルダ メソッドと同様のタスクを実行します。 distinct()メソッドの詳細については、「個別のフィールド値の取得」の使用例を参照してください。

ドキュメントの出力順序を指定するには、 sort()メソッドを集計パイプラインにチェーンできます。

この集計ステージは、パイプラインのどこにでも追加できます。 グループ化されたデータに依存する可能性があるため、グループ ステージの後に配置されることが多い。 処理されるデータを制限するために、ソート ステージを可能な限りパイプラインの末尾に配置することをお勧めします。

並べ替えを指定するには、フィールド値を 昇順ソート の場合はSort::Asc列挙型に設定し、降順ソートの場合はSort::Desc列挙型に設定します。

この例では、ドキュメントをnameフィールドでSort::Descにソートするsort()集計パイプライン ステージが示されています。これはアルファベットの逆順に対応します。 コードの実行によって返されたドキュメントを確認するには、 VIEW OUTPUTボタンをクリックします。

$pipeline = User::aggregate()
->sort(name: Sort::Desc);
$result = $pipeline->get();
[
{
"_id": ...,
"name": "Janet Doe",
"occupation": "designer",
"birthday": {
"$date": {
"$numberLong": "541728000000"
}
}
},
{
"_id": ...,
"name": "Francois Soma",
"occupation": "engineer",
"birthday": {
"$date": {
"$numberLong": "886377600000"
}
}
},
{
"_id": ...,
"name": "Ellis Lee",
"occupation": "designer",
"birthday": {
"$date": {
"$numberLong": "834019200000"
}
}
},
{
"_id": ...,
"name": "Eliud Nkosana",
"occupation": "engineer",
"birthday": {
"$date": {
"$numberLong": "449884800000"
}
}
},
{
"_id": ...,
"name": "Bran Steafan",
"occupation": "engineer",
"birthday": {
"$date": {
"$numberLong": "894326400000"
}
}
},
{
"_id": ...,
"name": "Alda Gröndal",
"occupation": "engineer",
"birthday": {
"$date": {
"$numberLong": "1009843200000"
}
}
}
]

project()メソッドを集計パイプラインにチェーンして、このステージで表示するドキュメントのフィールドを指定できます。

含めるフィールドを指定するには、フィールドの名前と1trueなどの真実の値を渡します。 他のすべてのフィールドは出力から省略されます。

あるいは、除外するフィールドを指定するには、各フィールド名と誤った値( 0falseなど)を渡します。 他のすべてのフィールドは出力に含まれます。

Tip

含めるフィールドを指定すると、 _idフィールドがデフォルトで含まれます。 _idフィールドを除外するには、プロジェクション ステージで明示的に除外します。

この例では、 project()メソッド集計ステージを使用してnameフィールドのみを含め、他のすべてのフィールドを出力から除外する方法を示します。 コードの実行によって返されたデータを確認するには、 VIEW OUTPUTボタンをクリックします。

$pipeline = User::aggregate()
->project(_id: 0, name: 1);
$result = $pipeline->get();
[
{ "name": "Alda Gröndal" },
{ "name": "Francois Soma" },
{ "name": "Janet Doe" },
{ "name": "Eliud Nkosana" },
{ "name": "Bran Steafan" },
{ "name": "Ellis Lee" }
]

集計パイプラインを構築するには、Model::aggregate() メソッドを呼び出し、集計ステージを実行する順序で連鎖させます。このセクションの例は、サーバー マニュアルを使用しています。各例には、データベースに挿入して集計操作をテストできるサンプルデータへのリンクが記載されています。

このセクションでは、一般的な集計ステージの使用方法を示す次の例を紹介します。

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

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

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

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

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

コードの実行によって返されるデータを確認するには、[ VIEW OUTPUT ] ボタンをクリックします。

$pipeline = Sale::aggregate()
->match(
date: [
Query::gte(new UTCDateTime(new DateTimeImmutable('2014-01-01'))),
Query::lt(new UTCDateTime(new DateTimeImmutable('2015-01-01'))),
],
)
->group(
_id: Expression::dateToString(Expression::dateFieldPath('date'), '%Y-%m-%d'),
totalSaleAmount: Accumulator::sum(
Expression::multiply(
Expression::numberFieldPath('price'),
Expression::numberFieldPath('quantity'),
),
),
averageQuantity: Accumulator::avg(
Expression::numberFieldPath('quantity'),
),
count: Accumulator::sum(1),
)
->sort(
totalSaleAmount: Sort::Desc,
);
[
{ "_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 ステージ: ドキュメントをタグの値でグループ化し、各タグを持つアイテムの合計売上額を計算します。

コードの実行によって返されるデータを確認するには、[ VIEW OUTPUT ] ボタンをクリックします。

$pipeline = Sale::aggregate()
->unwind(Expression::arrayFieldPath('items'))
->unwind(Expression::arrayFieldPath('items.tags'))
->group(
_id: Expression::fieldPath('items.tags'),
totalSalesAmount: Accumulator::sum(
Expression::multiply(
Expression::numberFieldPath('items.price'),
Expression::numberFieldPath('items.quantity'),
),
),
);
[
{ "_id": "school", "totalSalesAmount": { "$numberDecimal": "104.85" } },
{ "_id": "electronics", "totalSalesAmount": { "$numberDecimal": "800.00" } },
{ "_id": "writing", "totalSalesAmount": { "$numberDecimal": "60.00" } },
{ "_id": "office", "totalSalesAmount": { "$numberDecimal": "1019.60" } },
{ "_id": "stationary", "totalSalesAmount": { "$numberDecimal": "264.45" } }
]

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

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

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

コードの実行によって返されるデータを確認するには、[ VIEW OUTPUT ] ボタンをクリックします。

$pipeline = Order::aggregate()
->lookup(
from: 'inventory',
localField: 'item',
foreignField: 'sku',
as: 'inventory_docs',
);
[
{ "_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 }
] }
]

集計ビルダー を使用して集計パイプラインを作成する場合、カスタム演算子ファクトリーで操作またはステージを定義できます。 カスタム演算子ファクトリーは、 集計パイプライン の式またはステージを返す関数です。 これらの関数を作成すると、コードの読みやすさと再利用を向上させることができます。

この例では、指定された日付フィールドから年を抽出する式を返すカスタム演算子ファクトリを作成して使用する方法を示します。

次の関数は、日付を含むフィールドの名前を受け入れ、日付から年を抽出する式を返します。

public function yearFromField(string $dateFieldName): YearOperator
{
return Expression::year(
Expression::dateFieldPath($dateFieldName),
);
}

サンプル集計パイプラインには、次のステージが含まれています。

  • addFields()はカスタム演算子ファクトリー関数を呼び出して、 birthdayフィールドから年を抽出し、それをbirth_yearフィールドに割り当てます。

  • project()は出力にname フィールドとbirth_year フィールドのみを含む

コードの実行によって返されるデータを確認するには、[ VIEW OUTPUT ] ボタンをクリックします。

$pipeline = User::aggregate()
->addFields(birth_year: $this->yearFromField('birthday'))
->project(_id: 0, name: 1, birth_year: 1);
[
{
"name": "Alda Gröndal",
"birth_year": 2002
},
{
"name": "Francois Soma",
"birth_year": 1998
},
{
"name": "Janet Doe",
"birth_year": 1987
},
{
"name": "Eliud Nkosana",
"birth_year": 1984
},
{
"name": "Bran Steafan",
"birth_year": 1998
},
{
"name": "Ellis Lee",
"birth_year": 1996
}
]