From 99d6179f6323a68ec499bf989a1fbaf823f36c54 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 10 Feb 2025 12:56:58 -0500 Subject: [PATCH 1/8] DOCSP-43919: aggregation builder --- snooty.toml | 1 + source/aggregation.txt | 225 ++++++++++++++++++-- source/includes/aggregation/aggregation.php | 105 +++++++-- source/whats-new.txt | 5 + 4 files changed, 305 insertions(+), 31 deletions(-) diff --git a/snooty.toml b/snooty.toml index f8b6d380..2d2e7384 100644 --- a/snooty.toml +++ b/snooty.toml @@ -41,6 +41,7 @@ php-library = "MongoDB PHP Library" [constants] php-library = "MongoDB PHP Library" version = "1.20" +source-gh-branch = "v1.x" full-version = "{+version+}.0" extension-short = "PHP extension" mdb-server = "MongoDB Server" diff --git a/source/aggregation.txt b/source/aggregation.txt index 527a9626..12988be3 100644 --- a/source/aggregation.txt +++ b/source/aggregation.txt @@ -47,8 +47,8 @@ The **aggregation pipeline** is the assembly line, **aggregation stages** are th assembly stations, and **operator expressions** are the specialized tools. -Aggregation Versus Find Operations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Compare Aggregation and Find Operations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can use find operations to perform the following actions: @@ -82,20 +82,46 @@ Consider the following limitations when performing aggregation operations: ` stage has a strict memory limit of 100 megabytes and ignores the ``allowDiskUse`` option. -.. _php-aggregation-example: +Aggregation APIs +---------------- -Aggregation Example -------------------- +The {+library-short+} provides the following APIs to create aggregation +pipelines: -.. note:: +- :ref:`php-aggregation-array-api`: Create aggregation pipelines by + passing arrays that specify the aggregation operators and parameters +- :ref:`php-aggregation-builder-api`: Create aggregation pipelines by using native + classes and methods to make your application more type-safe and debuggable + +The following sections describe each API and provide examples for +creating aggregation pipelines. + +.. _php-aggregation-array-api: - The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` - database from the :atlas:`Atlas sample datasets `. To learn how to create a - free MongoDB Atlas cluster and load the sample datasets, see the :atlas:`Get Started with Atlas - ` guide. +Array API +--------- -To perform an aggregation, pass an array containing the pipeline stages to -the ``MongoDB\Collection::aggregate()`` method. +To perform an aggregation, pass an array containing the pipeline stages +as BSON documents to the ``MongoDB\Collection::aggregate()`` method, as +shown in the following code: + +.. code-block:: php + + $pipeline = [ + ['' => ], + ['' => ], + ... + ]; + + $cursor = $collection->aggregate($pipeline); + +The examples in this section use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To learn how to create a +free MongoDB Atlas cluster and load the sample datasets, see the :atlas:`Get Started with Atlas +` guide. + +Filter and Group Example +~~~~~~~~~~~~~~~~~~~~~~~~ The following code example produces a count of the number of bakeries in each borough of New York. To do so, it uses an aggregation pipeline that contains the following stages: @@ -110,9 +136,9 @@ of New York. To do so, it uses an aggregation pipeline that contains the followi .. io-code-block:: :copyable: - .. input:: /includes/aggregation/aggregation.php - :start-after: start-match-group - :end-before: end-match-group + .. input:: /includes/aggregation.php + :start-after: start-array-match-group + :end-before: end-array-match-group :language: php :dedent: @@ -141,14 +167,14 @@ and pass the database, collection, and pipeline stages as parameters. Then, pass ``MongoDB\Operation\Aggregate`` object to the ``MongoDB\Collection::explain()`` method. The following example instructs MongoDB to explain the aggregation operation -from the preceding :ref:`php-aggregation-example`: +from the preceding section: .. io-code-block:: :copyable: - .. input:: /includes/aggregation/aggregation.php - :start-after: start-explain - :end-before: end-explain + .. input:: /includes/aggregation.php + :start-after: start-array-explain + :end-before: end-array-explain :language: php :dedent: @@ -161,6 +187,162 @@ from the preceding :ref:`php-aggregation-example`: "maxIndexedAndSolutionsReached":false,"maxScansToExplodeReached":false,"winningPlan":{ ... } +.. _php-aggregation-builder-api: + +Aggregation Builder +------------------- + +To create an aggregation pipeline by using the Aggregation Builder, +perform the following actions: + +#. Create a ``Pipeline`` class instance to initialize the pipeline + +#. Within the ``Pipeline`` instance, call an operator method from the ``Stage`` + builder class to create that type of aggregation stage + +#. Within the body of the ``Stage`` method, use methods from other + builder classes such as ``Query``, ``Expression``, or ``Accumulator`` + to express your aggregation specifications + +The following code demonstrates the template for constructing +aggregation pipelines: + +.. code-block:: php + + $pipeline = new Pipeline( + Stage::( + + ), + Stage::( + + ), + ... + ); + + $cursor = $collection->aggregate(iterator_to_array($pipeline)); + +.. note:: + + The preceding code uses the ``iterator_to_array()`` method to + convert the ``Pipeline`` instance into an array. You must call this method + on your ``Pipeline`` before passing it to the ``aggregate()`` method. + +The examples in this section are adapted from the {+mdb-server+} manual. +Each example provides a link to the sample data that you can insert into +your database to test the aggregation operation. + +Filter and Group Example +~~~~~~~~~~~~~~~~~~~~~~~~ + +This example uses the sample data given in the :manual:`Calculate Count, +Sum, and Average ` +section of the ``$group`` stage reference in the Server manual. + +The following code example calculates the total sales amount, average +sales quantity, and sale count for each day in the year 2014. To do so, +it uses an aggregation pipeline that contains the following stages: + +- :manual:`$match ` stage to + filter for documents that contain a ``date`` field in which the year is + 2014 + +- :manual:`$group ` stage to + group the documents by date and calculate the total sale amount, + average quantity, and total count for each group + +- :manual:`$sort ` stage to + sort the results by the total sale amount for each group in descending + order + +.. io-code-block:: + :copyable: + + .. input:: /includes/aggregation.php + :start-after: start-builder-match-group + :end-before: end-builder-match-group + :language: php + :dedent: + + .. output:: + :visible: false + + {"_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 Embedded Arrays Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example uses the sample data given in the :manual:`Unwind Embedded Arrays +` +section of the ``$unwind`` stage reference in the Server manual. + +The following code example groups sold items by their tags and +calculates the total sales amount for each tag. To do so, +it uses an aggregation pipeline that contains the following stages: + +- :manual:`$unwind ` stage to + output a separate document for each element in the ``items`` array + +- :manual:`$unwind ` stage to + output a separate document for each element in the ``items.tags`` arrays + +- :manual:`$group ` stage to + group the documents by the tag value and calculates the total sales + amount of items that have each tag + +.. io-code-block:: + :copyable: + + .. input:: /includes/aggregation.php + :start-after: start-builder-unwind + :end-before: end-builder-unwind + :language: php + :dedent: + + .. output:: + :visible: false + + {"_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"}} + +Single Equality Join Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example uses the sample data given in the :manual:`Perform a Single +Equality Join with $lookup +` +section of the ``$lookup`` stage reference in the Server manual. + +The following code example joins the documents from the ``orders`` +collection with the documents from the ``inventory`` collection by using +the ``item`` field from the ``orders`` collection and the ``sku`` field +from the ``inventory`` collection. + +To do so, the example uses an aggregation pipeline that contains a +:manual:`$lookup ` stage that +specifies the collection to retrieve data from and the local and +foreign field names. + +.. io-code-block:: + :copyable: + + .. input:: /includes/aggregation.php + :start-after: start-builder-lookup + :end-before: end-builder-lookup + :language: php + :dedent: + + .. output:: + :visible: false + + {"_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}]} + Additional Information ---------------------- @@ -169,6 +351,11 @@ pipelines, see `Complex Aggregation Pipelines with Vanilla PHP and MongoDB `__ in the MongoDB Developer Center. +To view more examples of aggregation pipelines built by using the Aggregation +Builder, see the :github:`Stage class test suite +` in the +{+library-short+} source code on GitHub. + MongoDB Server Manual ~~~~~~~~~~~~~~~~~~~~~ diff --git a/source/includes/aggregation/aggregation.php b/source/includes/aggregation/aggregation.php index e8b1a7f9..b9aa06b4 100644 --- a/source/includes/aggregation/aggregation.php +++ b/source/includes/aggregation/aggregation.php @@ -1,4 +1,13 @@ ['cuisine' => 'Bakery']], - ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], + ['$match' => ['cuisine' => 'Bakery']], + ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], ]; $cursor = $collection->aggregate($pipeline); foreach ($cursor as $doc) { - echo json_encode($doc), PHP_EOL; + echo json_encode($doc), PHP_EOL; } -// end-match-group +// end-array-match-group // Performs the same aggregation operation as above but asks MongoDB to explain it -// start-explain +// start-array-explain $pipeline = [ - ['$match' => ['cuisine' => 'Bakery']], - ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], + ['$match' => ['cuisine' => 'Bakery']], + ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], ]; $aggregate = new MongoDB\Operation\Aggregate( - $collection->getDatabaseName(), - $collection->getCollectionName(), - $pipeline + $collection->getDatabaseName(), + $collection->getCollectionName(), + $pipeline ); $result = $collection->explain($aggregate); echo json_encode($result), PHP_EOL; -// end-explain +// end-array-explain + +// start-builder-match-group +$pipeline = new Pipeline( + Stage::match( + date: [ + Query::gte(new UTCDateTime(new DateTimeImmutable('2014-01-01'))), + Query::lt(new UTCDateTime(new DateTimeImmutable('2015-01-01'))), + ], + ), + Stage::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), + ), + Stage::sort( + totalSaleAmount: Sort::Desc, + ), +); + +$cursor = $collection->aggregate(iterator_to_array($pipeline)); + +foreach ($cursor as $doc) { + echo json_encode($doc), PHP_EOL; +} +// end-builder-match-group + +// start-builder-unwind +$pipeline = new Pipeline( + Stage::unwind(Expression::arrayFieldPath('items')), + Stage::unwind(Expression::arrayFieldPath('items.tags')), + Stage::group( + _id: Expression::fieldPath('items.tags'), + totalSalesAmount: Accumulator::sum( + Expression::multiply( + Expression::numberFieldPath('items.price'), + Expression::numberFieldPath('items.quantity'), + ), + ), + ), +); +$cursor = $collection->aggregate(iterator_to_array($pipeline)); + +foreach ($cursor as $doc) { + echo json_encode($doc), PHP_EOL; +} +// end-builder-unwind + +// start-builder-lookup +$pipeline = new Pipeline( + Stage::lookup( + from: 'inventory', + localField: 'item', + foreignField: 'sku', + as: 'inventory_docs', + ), +); + +/* Perform the aggregation on the orders collection */ +$cursor = $collection->aggregate(iterator_to_array($pipeline)); + +foreach ($cursor as $doc) { + echo json_encode($doc), PHP_EOL; +} +// end-builder-lookup diff --git a/source/whats-new.txt b/source/whats-new.txt index 62b87004..83cc6dbd 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -38,6 +38,11 @@ What's New in 1.21 The {+library-short+} v1.21 release includes the following features, improvements, and fixes: +- Introduces the Aggregation Builder as an API to build aggregation + pipelines in a more type-safe and PHP-native way. To learn more and + view examples, see the :ref:`php-aggregation-builder-api` section of + the Aggregation guide. + - Adds the following methods: - :phpmethod:`MongoDB\Client::getDatabase()`: alias for :phpmethod:`MongoDB\Client::selectDatabase()` From ddc1e57f784956743c57699481cc3674689d9fc5 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 10 Feb 2025 12:59:48 -0500 Subject: [PATCH 2/8] indentation fix --- source/includes/aggregation/aggregation.php | 100 ++++++++++---------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/source/includes/aggregation/aggregation.php b/source/includes/aggregation/aggregation.php index b9aa06b4..003ee4b3 100644 --- a/source/includes/aggregation/aggregation.php +++ b/source/includes/aggregation/aggregation.php @@ -19,28 +19,28 @@ // counts each borough's matching documents // start-array-match-group $pipeline = [ - ['$match' => ['cuisine' => 'Bakery']], - ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], + ['$match' => ['cuisine' => 'Bakery']], + ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], ]; $cursor = $collection->aggregate($pipeline); foreach ($cursor as $doc) { - echo json_encode($doc), PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-array-match-group // Performs the same aggregation operation as above but asks MongoDB to explain it // start-array-explain $pipeline = [ - ['$match' => ['cuisine' => 'Bakery']], - ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], + ['$match' => ['cuisine' => 'Bakery']], + ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], ]; $aggregate = new MongoDB\Operation\Aggregate( - $collection->getDatabaseName(), - $collection->getCollectionName(), - $pipeline + $collection->getDatabaseName(), + $collection->getCollectionName(), + $pipeline ); $result = $collection->explain($aggregate); @@ -49,73 +49,73 @@ // start-builder-match-group $pipeline = new Pipeline( - Stage::match( - date: [ - Query::gte(new UTCDateTime(new DateTimeImmutable('2014-01-01'))), - Query::lt(new UTCDateTime(new DateTimeImmutable('2015-01-01'))), - ], - ), - Stage::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), - ), - Stage::sort( - totalSaleAmount: Sort::Desc, - ), + Stage::match( + date: [ + Query::gte(new UTCDateTime(new DateTimeImmutable('2014-01-01'))), + Query::lt(new UTCDateTime(new DateTimeImmutable('2015-01-01'))), + ], + ), + Stage::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), + ), + Stage::sort( + totalSaleAmount: Sort::Desc, + ), ); $cursor = $collection->aggregate(iterator_to_array($pipeline)); foreach ($cursor as $doc) { - echo json_encode($doc), PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-builder-match-group // start-builder-unwind $pipeline = new Pipeline( - Stage::unwind(Expression::arrayFieldPath('items')), - Stage::unwind(Expression::arrayFieldPath('items.tags')), - Stage::group( - _id: Expression::fieldPath('items.tags'), - totalSalesAmount: Accumulator::sum( - Expression::multiply( - Expression::numberFieldPath('items.price'), - Expression::numberFieldPath('items.quantity'), - ), - ), - ), + Stage::unwind(Expression::arrayFieldPath('items')), + Stage::unwind(Expression::arrayFieldPath('items.tags')), + Stage::group( + _id: Expression::fieldPath('items.tags'), + totalSalesAmount: Accumulator::sum( + Expression::multiply( + Expression::numberFieldPath('items.price'), + Expression::numberFieldPath('items.quantity'), + ), + ), + ), ); $cursor = $collection->aggregate(iterator_to_array($pipeline)); foreach ($cursor as $doc) { - echo json_encode($doc), PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-builder-unwind // start-builder-lookup $pipeline = new Pipeline( - Stage::lookup( - from: 'inventory', - localField: 'item', - foreignField: 'sku', - as: 'inventory_docs', - ), + Stage::lookup( + from: 'inventory', + localField: 'item', + foreignField: 'sku', + as: 'inventory_docs', + ), ); /* Perform the aggregation on the orders collection */ $cursor = $collection->aggregate(iterator_to_array($pipeline)); foreach ($cursor as $doc) { - echo json_encode($doc), PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-builder-lookup From ce272b3eb530e2c8162caee4143e7c6a6231f8b7 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 10 Feb 2025 15:46:59 -0500 Subject: [PATCH 3/8] remov Pipeline type --- source/aggregation.txt | 16 +++++----------- source/includes/aggregation/aggregation.php | 19 +++++++++---------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/source/aggregation.txt b/source/aggregation.txt index 12988be3..e0c7a726 100644 --- a/source/aggregation.txt +++ b/source/aggregation.txt @@ -195,9 +195,9 @@ Aggregation Builder To create an aggregation pipeline by using the Aggregation Builder, perform the following actions: -#. Create a ``Pipeline`` class instance to initialize the pipeline +#. Create an array to store the pipeline stages -#. Within the ``Pipeline`` instance, call an operator method from the ``Stage`` +#. For each stage, call an operator method from the ``Stage`` builder class to create that type of aggregation stage #. Within the body of the ``Stage`` method, use methods from other @@ -209,7 +209,7 @@ aggregation pipelines: .. code-block:: php - $pipeline = new Pipeline( + $pipeline = [ Stage::( ), @@ -217,15 +217,9 @@ aggregation pipelines: ), ... - ); + ]; - $cursor = $collection->aggregate(iterator_to_array($pipeline)); - -.. note:: - - The preceding code uses the ``iterator_to_array()`` method to - convert the ``Pipeline`` instance into an array. You must call this method - on your ``Pipeline`` before passing it to the ``aggregate()`` method. + $cursor = $collection->aggregate($pipeline); The examples in this section are adapted from the {+mdb-server+} manual. Each example provides a link to the sample data that you can insert into diff --git a/source/includes/aggregation/aggregation.php b/source/includes/aggregation/aggregation.php index 003ee4b3..0dba65db 100644 --- a/source/includes/aggregation/aggregation.php +++ b/source/includes/aggregation/aggregation.php @@ -3,7 +3,6 @@ use MongoDB\BSON\UTCDateTime; use MongoDB\Builder\Accumulator; use MongoDB\Builder\Expression; -use MongoDB\Builder\Pipeline; use MongoDB\Builder\Query; use MongoDB\Builder\Stage; use MongoDB\Builder\Type\Sort; @@ -48,7 +47,7 @@ // end-array-explain // start-builder-match-group -$pipeline = new Pipeline( +$pipeline = [ Stage::match( date: [ Query::gte(new UTCDateTime(new DateTimeImmutable('2014-01-01'))), @@ -71,9 +70,9 @@ Stage::sort( totalSaleAmount: Sort::Desc, ), -); +]; -$cursor = $collection->aggregate(iterator_to_array($pipeline)); +$cursor = $collection->aggregate($pipeline); foreach ($cursor as $doc) { echo json_encode($doc), PHP_EOL; @@ -81,7 +80,7 @@ // end-builder-match-group // start-builder-unwind -$pipeline = new Pipeline( +$pipeline = [ Stage::unwind(Expression::arrayFieldPath('items')), Stage::unwind(Expression::arrayFieldPath('items.tags')), Stage::group( @@ -93,9 +92,9 @@ ), ), ), -); +]; -$cursor = $collection->aggregate(iterator_to_array($pipeline)); +$cursor = $collection->aggregate($pipeline); foreach ($cursor as $doc) { echo json_encode($doc), PHP_EOL; @@ -103,17 +102,17 @@ // end-builder-unwind // start-builder-lookup -$pipeline = new Pipeline( +$pipeline = [ Stage::lookup( from: 'inventory', localField: 'item', foreignField: 'sku', as: 'inventory_docs', ), -); +]; /* Perform the aggregation on the orders collection */ -$cursor = $collection->aggregate(iterator_to_array($pipeline)); +$cursor = $collection->aggregate($pipeline); foreach ($cursor as $doc) { echo json_encode($doc), PHP_EOL; From 70bcf6c253a48af2ec1c6fa5658e4a45e3137095 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 11 Feb 2025 14:28:47 -0500 Subject: [PATCH 4/8] LM PR fixes 1 --- source/aggregation.txt | 57 +++++++++++---------- source/aggregation/atlas-search.txt | 6 +-- source/aggregation/vector-search.txt | 6 +-- source/includes/aggregation/aggregation.php | 2 +- source/whats-new.txt | 2 +- 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/source/aggregation.txt b/source/aggregation.txt index e0c7a726..92605fb6 100644 --- a/source/aggregation.txt +++ b/source/aggregation.txt @@ -72,6 +72,7 @@ Consider the following limitations when performing aggregation operations: - Returned documents cannot violate the :manual:`BSON document size limit ` of 16 megabytes. + - Pipeline stages have a memory limit of 100 megabytes by default. You can exceed this limit by creating an options array that sets the ``allowDiskUse`` option to ``true`` and passing the array to the ``MongoDB\Collection::aggregate()`` method. @@ -89,9 +90,9 @@ The {+library-short+} provides the following APIs to create aggregation pipelines: - :ref:`php-aggregation-array-api`: Create aggregation pipelines by - passing arrays that specify the aggregation operators and parameters + passing arrays that specify the aggregation operators and parameters. - :ref:`php-aggregation-builder-api`: Create aggregation pipelines by using native - classes and methods to make your application more type-safe and debuggable + classes and methods to make your application more type-safe and debuggable. The following sections describe each API and provide examples for creating aggregation pipelines. @@ -126,12 +127,12 @@ Filter and Group Example The following code example produces a count of the number of bakeries in each borough of New York. To do so, it uses an aggregation pipeline that contains the following stages: -- :manual:`$match ` stage to filter for documents - in which the ``cuisine`` field contains the value ``'Bakery'`` +1. :manual:`$match ` stage to filter for documents + in which the ``cuisine`` field contains the value ``'Bakery'`` -- :manual:`$group ` stage to group the matching - documents by the ``borough`` field, accumulating a count of documents for each distinct - value +#. :manual:`$group ` stage to group the matching + documents by the ``borough`` field, accumulating a count of documents for each distinct + value .. io-code-block:: :copyable: @@ -195,14 +196,16 @@ Aggregation Builder To create an aggregation pipeline by using the Aggregation Builder, perform the following actions: -#. Create an array to store the pipeline stages +1. Create an array to store the pipeline stages. -#. For each stage, call an operator method from the ``Stage`` - builder class to create that type of aggregation stage +#. For each stage, call the an operator method from the + ``Stage`` that shares the same name as your desired aggregation + stage. For example, to create an ``$unwind`` stage, call the + ``Stage::unwind()`` method. #. Within the body of the ``Stage`` method, use methods from other builder classes such as ``Query``, ``Expression``, or ``Accumulator`` - to express your aggregation specifications + to express your aggregation specifications. The following code demonstrates the template for constructing aggregation pipelines: @@ -236,17 +239,17 @@ The following code example calculates the total sales amount, average sales quantity, and sale count for each day in the year 2014. To do so, it uses an aggregation pipeline that contains the following stages: -- :manual:`$match ` stage to - filter for documents that contain a ``date`` field in which the year is - 2014 +1. :manual:`$match ` stage to + filter for documents that contain a ``date`` field in which the year is + 2014 -- :manual:`$group ` stage to - group the documents by date and calculate the total sale amount, - average quantity, and total count for each group +#. :manual:`$group ` stage to + group the documents by date and calculate the total sale amount, + average quantity, and total count for each group -- :manual:`$sort ` stage to - sort the results by the total sale amount for each group in descending - order +#. :manual:`$sort ` stage to + sort the results by the total sale amount for each group in descending + order .. io-code-block:: :copyable: @@ -275,15 +278,15 @@ The following code example groups sold items by their tags and calculates the total sales amount for each tag. To do so, it uses an aggregation pipeline that contains the following stages: -- :manual:`$unwind ` stage to - output a separate document for each element in the ``items`` array +1. :manual:`$unwind ` stage to + output a separate document for each element in the ``items`` array -- :manual:`$unwind ` stage to - output a separate document for each element in the ``items.tags`` arrays +#. :manual:`$unwind ` stage to + output a separate document for each element in the ``items.tags`` arrays -- :manual:`$group ` stage to - group the documents by the tag value and calculates the total sales - amount of items that have each tag +#. :manual:`$group ` stage to + group the documents by the tag value and calculates the total sales + amount of items that have each tag .. io-code-block:: :copyable: diff --git a/source/aggregation/atlas-search.txt b/source/aggregation/atlas-search.txt index d47ac750..83e65225 100644 --- a/source/aggregation/atlas-search.txt +++ b/source/aggregation/atlas-search.txt @@ -66,12 +66,12 @@ Search queries by using the Aggregation Builder: To create a ``$search`` stage in your aggregation pipeline, perform the following actions: -1. Create an array to store the pipeline stages +1. Create an array to store the pipeline stages. -#. Call the ``Stage::search()`` method to create the Atlas Search stage +#. Call the ``Stage::search()`` method to create the Atlas Search stage. #. Within the body of the ``search()`` method, use methods from the - ``Search`` builder class to construct your Search query criteria + ``Search`` builder class to construct your Search query criteria. The following code demonstrates the template for constructing basic Atlas Search queries: diff --git a/source/aggregation/vector-search.txt b/source/aggregation/vector-search.txt index b9ca56dc..ea0b57b3 100644 --- a/source/aggregation/vector-search.txt +++ b/source/aggregation/vector-search.txt @@ -67,13 +67,13 @@ Search queries by using the Aggregation Builder: To create a ``$vectorSearch`` stage in your aggregation pipeline, perform the following actions: -1. Create an array to store the pipeline stages +1. Create an array to store the pipeline stages. #. Call the ``Stage::vectorSearch()`` method to create the Atlas Vector - Search stage + Search stage. #. Within the body of the ``vectorSearch()`` method, specify the - criteria for your vector query + criteria for your vector query. The following code demonstrates the template for constructing basic Atlas Search queries: diff --git a/source/includes/aggregation/aggregation.php b/source/includes/aggregation/aggregation.php index 0dba65db..91272f5c 100644 --- a/source/includes/aggregation/aggregation.php +++ b/source/includes/aggregation/aggregation.php @@ -111,7 +111,7 @@ ), ]; -/* Perform the aggregation on the orders collection */ +/* Performs the aggregation on the orders collection */ $cursor = $collection->aggregate($pipeline); foreach ($cursor as $doc) { diff --git a/source/whats-new.txt b/source/whats-new.txt index 83cc6dbd..d7fff94e 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -38,7 +38,7 @@ What's New in 1.21 The {+library-short+} v1.21 release includes the following features, improvements, and fixes: -- Introduces the Aggregation Builder as an API to build aggregation +- Introduces the Aggregation Builder, an API to build aggregation pipelines in a more type-safe and PHP-native way. To learn more and view examples, see the :ref:`php-aggregation-builder-api` section of the Aggregation guide. From 9707107129cffb0193270ee33cca6f7441723ad5 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 11 Feb 2025 14:44:43 -0500 Subject: [PATCH 5/8] fp fixes --- source/aggregation.txt | 10 +++++----- source/aggregation/atlas-search.txt | 3 +-- source/aggregation/vector-search.txt | 3 +-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/source/aggregation.txt b/source/aggregation.txt index 92605fb6..5c49225f 100644 --- a/source/aggregation.txt +++ b/source/aggregation.txt @@ -137,7 +137,7 @@ of New York. To do so, it uses an aggregation pipeline that contains the followi .. io-code-block:: :copyable: - .. input:: /includes/aggregation.php + .. input:: /includes/aggregation/aggregation.php :start-after: start-array-match-group :end-before: end-array-match-group :language: php @@ -173,7 +173,7 @@ from the preceding section: .. io-code-block:: :copyable: - .. input:: /includes/aggregation.php + .. input:: /includes/aggregation/aggregation.php :start-after: start-array-explain :end-before: end-array-explain :language: php @@ -254,7 +254,7 @@ it uses an aggregation pipeline that contains the following stages: .. io-code-block:: :copyable: - .. input:: /includes/aggregation.php + .. input:: /includes/aggregation/aggregation.php :start-after: start-builder-match-group :end-before: end-builder-match-group :language: php @@ -291,7 +291,7 @@ it uses an aggregation pipeline that contains the following stages: .. io-code-block:: :copyable: - .. input:: /includes/aggregation.php + .. input:: /includes/aggregation/aggregation.php :start-after: start-builder-unwind :end-before: end-builder-unwind :language: php @@ -327,7 +327,7 @@ foreign field names. .. io-code-block:: :copyable: - .. input:: /includes/aggregation.php + .. input:: /includes/aggregation/aggregation.php :start-after: start-builder-lookup :end-before: end-builder-lookup :language: php diff --git a/source/aggregation/atlas-search.txt b/source/aggregation/atlas-search.txt index 83e65225..8846459f 100644 --- a/source/aggregation/atlas-search.txt +++ b/source/aggregation/atlas-search.txt @@ -22,8 +22,7 @@ Overview In this guide, you can learn how to perform searches on your documents by using the Atlas Search feature. The {+library-short+} allows you to -perform Atlas Search queries by using the :ref:`Aggregation Builder API -`. +perform Atlas Search queries by using the :ref:`php-aggregation-builder-api`. .. note:: Deployment Compatibility diff --git a/source/aggregation/vector-search.txt b/source/aggregation/vector-search.txt index ea0b57b3..c1396ac7 100644 --- a/source/aggregation/vector-search.txt +++ b/source/aggregation/vector-search.txt @@ -22,8 +22,7 @@ Overview In this guide, you can learn how to perform searches on your documents by using the Atlas Vector Search feature. The {+library-short+} allows you to -perform Atlas Vector Search queries by using the :ref:`Aggregation Builder API -`. +perform Atlas Vector Search queries by using the :ref:`php-aggregation-builder-api`. .. note:: Deployment Compatibility From 38bc143d196db8c24008c9ef8d84511f1026f654 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 11 Feb 2025 14:48:39 -0500 Subject: [PATCH 6/8] todo fixes --- .github/workflows/coding-standards.yml | 4 +--- .github/workflows/static-analysis.yml | 4 +--- source/indexes/atlas-search-index.txt | 10 ++++------ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 30012e46..18961eb7 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -8,9 +8,7 @@ on: env: PHP_VERSION: "8.2" - # TODO: change to "stable" once 1.20.0 is released - # DRIVER_VERSION: "stable" - DRIVER_VERSION: "mongodb/mongo-php-driver@master" + DRIVER_VERSION: "stable" jobs: phpcs: diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index ef58d7c5..3a655b5f 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -14,9 +14,7 @@ on: env: PHP_VERSION: "8.2" - # TODO: change to "stable" once 1.20.0 is released - # DRIVER_VERSION: "stable" - DRIVER_VERSION: "mongodb/mongo-php-driver@master" + DRIVER_VERSION: "stable" jobs: psalm: diff --git a/source/indexes/atlas-search-index.txt b/source/indexes/atlas-search-index.txt index c3d8fce4..8b6a1c50 100644 --- a/source/indexes/atlas-search-index.txt +++ b/source/indexes/atlas-search-index.txt @@ -86,13 +86,11 @@ Vector Search indexes in one call: :end-before: end-create-multiple-indexes After you create Atlas Search or Atlas Vector Search indexes, you can -perform the corresponding query types on your documents. +perform the corresponding query types on your documents. To learn more, +see the following guides: -.. - TODO uncomment when https://github.com/mongodb/docs-php-library/pull/197 is merged - To learn more, see the following guides: - - :ref:`php-atlas-search` - - :ref:`php-vector-search` +- :ref:`php-atlas-search` guide +- :ref:`php-vector-search` guide .. _php-atlas-search-index-list: From 5f5266d40465978028176a7b7d5fba6694a38a2f Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 12 Feb 2025 12:09:32 -0500 Subject: [PATCH 7/8] small fixes --- source/aggregation.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/aggregation.txt b/source/aggregation.txt index 5c49225f..f7eee6dc 100644 --- a/source/aggregation.txt +++ b/source/aggregation.txt @@ -244,8 +244,8 @@ it uses an aggregation pipeline that contains the following stages: 2014 #. :manual:`$group ` stage to - group the documents by date and calculate the total sale amount, - average quantity, and total count for each group + group the documents by date and calculate the total sales amount, + average sales quantity, and sale count for each group #. :manual:`$sort ` stage to sort the results by the total sale amount for each group in descending @@ -285,7 +285,7 @@ it uses an aggregation pipeline that contains the following stages: output a separate document for each element in the ``items.tags`` arrays #. :manual:`$group ` stage to - group the documents by the tag value and calculates the total sales + group the documents by the tag value and calculate the total sales amount of items that have each tag .. io-code-block:: From 948fc355ba1d56205fd8e67eb476d66925755044 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 13 Feb 2025 11:59:51 -0500 Subject: [PATCH 8/8] JM tech review 1 --- source/aggregation.txt | 16 +++--- source/includes/aggregation/aggregation.php | 55 ++++++++++----------- source/whats-new.txt | 2 +- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/source/aggregation.txt b/source/aggregation.txt index f7eee6dc..2ec29c8f 100644 --- a/source/aggregation.txt +++ b/source/aggregation.txt @@ -90,9 +90,9 @@ The {+library-short+} provides the following APIs to create aggregation pipelines: - :ref:`php-aggregation-array-api`: Create aggregation pipelines by - passing arrays that specify the aggregation operators and parameters. -- :ref:`php-aggregation-builder-api`: Create aggregation pipelines by using native - classes and methods to make your application more type-safe and debuggable. + passing arrays that specify the aggregation stages. +- :ref:`php-aggregation-builder-api`: Create aggregation pipelines by + using factory methods to make your application more type-safe and debuggable. The following sections describe each API and provide examples for creating aggregation pipelines. @@ -109,8 +109,8 @@ shown in the following code: .. code-block:: php $pipeline = [ - ['' => ], - ['' => ], + ['' => ], + ['' => ], ... ]; @@ -198,7 +198,7 @@ perform the following actions: 1. Create an array to store the pipeline stages. -#. For each stage, call the an operator method from the +#. For each stage, call the a factory method from the ``Stage`` that shares the same name as your desired aggregation stage. For example, to create an ``$unwind`` stage, call the ``Stage::unwind()`` method. @@ -213,10 +213,10 @@ aggregation pipelines: .. code-block:: php $pipeline = [ - Stage::( + Stage::( ), - Stage::( + Stage::( ), ... diff --git a/source/includes/aggregation/aggregation.php b/source/includes/aggregation/aggregation.php index 91272f5c..5aa56684 100644 --- a/source/includes/aggregation/aggregation.php +++ b/source/includes/aggregation/aggregation.php @@ -1,12 +1,5 @@ db->orders; + // start-builder-lookup $pipeline = [ - Stage::lookup( + MongoDB\Builder\Stage::lookup( from: 'inventory', localField: 'item', foreignField: 'sku', diff --git a/source/whats-new.txt b/source/whats-new.txt index d7fff94e..ab6a7a9e 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -39,7 +39,7 @@ The {+library-short+} v1.21 release includes the following features, improvements, and fixes: - Introduces the Aggregation Builder, an API to build aggregation - pipelines in a more type-safe and PHP-native way. To learn more and + pipelines in a more type-safe way. To learn more and view examples, see the :ref:`php-aggregation-builder-api` section of the Aggregation guide.