diff --git a/config/redirects b/config/redirects
index 888fd165..ed07f30c 100644
--- a/config/redirects
+++ b/config/redirects
@@ -1,5 +1,6 @@
define: prefix docs/languages/python/pymongo-driver
define: base https://www.mongodb.com/${prefix}
+define: server https://www.mongodb.com/docs/manual
define: versions v4.0 v4.1 v4.2 v4.3 v4.4 v4.5 v4.6 v4.7 v4.8 v4.9 v4.10 v4.11 v4.12 v4.13 master
symlink: current -> master
@@ -169,10 +170,16 @@ raw: ${prefix}/security/authentication/kerberos/ -> ${base}/current/security/aut
[*-master]: ${prefix}/${version}/indexes/wildcard-index/ -> ${base}/${version}/indexes/
[*-master]: ${prefix}/${version}/indexes/clustered-index/ -> ${base}/${version}/indexes/
+# Aggregation tutorials redirects
[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/ -> ${base}/${version}/aggregation/
-[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/filtered-subset/ -> ${base}/${version}/aggregation/filtered-subset/
-[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/group-total/ -> ${base}/${version}/aggregation/group-total/
-[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/multi-field-join/ -> ${base}/${version}/aggregation/multi-field-join/
-[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/one-to-one-join/ -> ${base}/${version}/aggregation/one-to-one-join/
-[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/unpack-arrays/ -> ${base}/${version}/aggregation/unpack-arrays/
+[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/filtered-subset/ -> ${server}/tutorial/aggregation-examples/filtered-subset/
+[*-master]: ${prefix}/${version}/aggregation/filtered-subset/ -> ${server}/tutorial/aggregation-examples/filtered-subset/
+[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/group-total/ -> ${server}/tutorial/aggregation-examples/group-and-total/
+[*-master]: ${prefix}/${version}/aggregation/group-total/ -> ${server}/tutorial/aggregation-examples/group-and-total/
+[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/multi-field-join/ -> ${server}/tutorial/aggregation-examples/multi-field-join/
+[*-master]: ${prefix}/${version}/aggregation/multi-field-join/ -> ${server}/tutorial/aggregation-examples/multi-field-join/
+[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/one-to-one-join/ ->${server}/tutorial/aggregation-examples/one-to-one-join/
+[*-master]: ${prefix}/${version}/aggregation/one-to-one-join/ -> ${server}/tutorial/aggregation-examples/one-to-one-join/
+[*-master]: ${prefix}/${version}/aggregation/aggregation-tutorials/unpack-arrays/ -> ${server}/tutorial/aggregation-examples/unpack-arrays/
+[*-master]: ${prefix}/${version}/aggregation/unpack-arrays/ -> ${server}/tutorial/aggregation-examples/unpack-arrays/
diff --git a/snooty.toml b/snooty.toml
index 4078fc67..8b95c797 100644
--- a/snooty.toml
+++ b/snooty.toml
@@ -3,7 +3,6 @@ title = "PyMongo Driver"
toc_landing_pages = [
"/get-started",
"/connect",
- "/aggregation",
"/security",
"/security/authentication",
"/data-formats",
diff --git a/source/aggregation.txt b/source/aggregation.txt
index 7f0b6aa9..8d8e8d3a 100644
--- a/source/aggregation.txt
+++ b/source/aggregation.txt
@@ -18,16 +18,6 @@ Transform Your Data with Aggregation
:depth: 2
:class: singlecol
-.. toctree::
- :titlesonly:
- :maxdepth: 1
-
- Filtered Subset
- Group & Total
- Unpack Arrays & Group
- One-to-One Join
- Multi-Field Join
-
Overview
--------
@@ -50,6 +40,12 @@ The **aggregation pipeline** is the assembly line, **aggregation stages** are th
assembly stations, and **operator expressions** are the
specialized tools.
+.. sharedinclude:: dbx/agg-tutorials-manual-tip.rst
+
+ .. replacement:: language
+
+ :guilabel:`{+language+}`
+
Aggregation Versus Find Operations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -281,41 +277,6 @@ To learn more about explaining MongoDB operations, see
:manual:`Explain Output ` and
:manual:`Query Plans. `
-Aggregation Tutorials
-~~~~~~~~~~~~~~~~~~~~~
-
-To view step-by-step explanations of common aggregation tasks, see
-the following tutorials:
-
-- :ref:`pymongo-aggregation-filtered-subset`
-- :ref:`pymongo-aggregation-group-total`
-- :ref:`pymongo-aggregation-arrays`
-- :ref:`pymongo-aggregation-one-to-one`
-- :ref:`pymongo-aggregation-multi-field`
-
-Aggregation tutorials provide detailed explanations of common
-aggregation tasks in a step-by-step format. The tutorials are adapted
-from examples in the `Practical MongoDB Aggregations book
-`__ by Paul Done.
-
-Each tutorial includes the following sections:
-
-- **Introduction**, which describes the purpose and common use cases of the
- aggregation type. This section also describes the example and desired
- outcome that the tutorial demonstrates.
-
-- **Before You Get Started**, which describes the necessary databases,
- collections, and sample data that you must have before building the
- aggregation pipeline and performing the aggregation.
-
-- **Tutorial**, which describes how to build and run the aggregation
- pipeline. This section describes each stage of the completed
- aggregation tutorial, and then explains how to run and interpret the
- output of the aggregation.
-
-At the end of each aggregation tutorial, you can find a link to a fully
-runnable Python code file that you can run in your environment.
-
API Documentation
~~~~~~~~~~~~~~~~~
diff --git a/source/aggregation/filtered-subset.txt b/source/aggregation/filtered-subset.txt
deleted file mode 100644
index 8f59a273..00000000
--- a/source/aggregation/filtered-subset.txt
+++ /dev/null
@@ -1,218 +0,0 @@
-.. _pymongo-aggregation-filtered-subset:
-
-===============
-Filtered Subset
-===============
-
-.. contents:: On this page
- :local:
- :backlinks: none
- :depth: 2
- :class: singlecol
-
-.. facet::
- :name: genre
- :values: tutorial
-
-.. meta::
- :keywords: code example, python, sort, limit, aggregation
-
-Introduction
-------------
-
-In this tutorial, you can learn how to use {+driver-short+} to
-construct an aggregation pipeline, perform the
-aggregation on a collection, and print the results by completing and
-running a sample app. This aggregation performs the following operations:
-
-- Matches a subset of documents by a field value
-- Formats result documents
-
-Aggregation Task Summary
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-This tutorial demonstrates how to query a collection for a specific
-subset of documents in a collection. The results contain
-documents that describe the three youngest people who are engineers.
-
-This example uses one collection, ``persons``, which contains
-documents describing people. Each document includes a person's name,
-date of birth, vocation, and other details.
-
-Before You Get Started
-----------------------
-
-.. include:: /includes/aggregation-tutorial-intro.rst
-
-After you set up the app, access the ``persons`` collection by adding the
-following code to the application:
-
-.. literalinclude:: /includes/aggregation/filtered-subset.py
- :language: python
- :copyable: true
- :start-after: start-collection
- :end-before: end-collection
- :dedent:
-
-Delete any existing data in the collections and insert sample data into
-the ``persons`` collection as shown in the following code. Select the
-:guilabel:`Synchronous` or :guilabel:`Asynchronous` tab to see the corresponding code:
-
-.. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/filtered-subset.py
- :language: python
- :copyable: true
- :start-after: start-insert-persons
- :end-before: end-insert-persons
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/filtered-subset-async.py
- :language: python
- :copyable: true
- :start-after: start-insert-persons
- :end-before: end-insert-persons
- :dedent:
-
-Tutorial
---------
-
-.. procedure::
- :style: connected
-
- .. step:: Add a match stage for people who are engineers
-
- First, add a :manual:`$match
- ` stage that finds documents in which
- the value of the ``vocation`` field is ``"ENGINEER"``:
-
- .. literalinclude:: /includes/aggregation/filtered-subset.py
- :language: python
- :copyable: true
- :start-after: start-match
- :end-before: end-match
- :dedent:
-
- .. step:: Add a sort stage to sort from youngest to oldest
-
- Next, add a :manual:`$sort
- ` stage that sorts the
- documents in descending order by the ``dateofbirth`` field to
- list the youngest people first:
-
- .. literalinclude:: /includes/aggregation/filtered-subset.py
- :language: python
- :copyable: true
- :start-after: start-sort
- :end-before: end-sort
- :dedent:
-
- .. step:: Add a limit stage to see only three results
-
- Next, add a :manual:`$limit `
- stage to the pipeline to output only the first three documents in
- the results.
-
- .. literalinclude:: /includes/aggregation/filtered-subset.py
- :language: python
- :copyable: true
- :start-after: start-limit
- :end-before: end-limit
- :dedent:
-
- .. step:: Add an unset stage to remove unneeded fields
-
- Finally, add an :manual:`$unset
- ` stage. The
- ``$unset`` stage removes unnecessary fields from the result documents:
-
- .. literalinclude:: /includes/aggregation/filtered-subset.py
- :language: python
- :copyable: true
- :start-after: start-unset
- :end-before: end-unset
- :dedent:
-
- .. tip::
-
- Use the ``$unset`` operator instead of ``$project`` to avoid
- modifying the aggregation pipeline if documents with
- different fields are added to the collection.
-
- .. step:: Run the aggregation pipeline
-
- Add the following code to the end of your application to perform
- the aggregation on the ``persons`` collection. Select the :guilabel:`Synchronous` or
- :guilabel:`Asynchronous` tab to see the corresponding code:
-
- .. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/filtered-subset.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/filtered-subset-async.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- Finally, run the following command in your shell to start your
- application:
-
- .. code-block:: bash
-
- python3 agg_tutorial.py
-
- .. step:: Interpret results
-
- The aggregated result contains three documents. The documents
- represent the three youngest people with the vocation of ``"ENGINEER"``,
- ordered from youngest to oldest. The results omit the ``_id`` and ``address``
- fields.
-
- .. code-block:: javascript
- :copyable: false
-
- {
- 'person_id': '7363626383',
- 'firstname': 'Carl',
- 'lastname': 'Simmons',
- 'dateofbirth': datetime.datetime(1998, 12, 26, 13, 13, 55),
- 'vocation': 'ENGINEER'
- }
- {
- 'person_id': '1723338115',
- 'firstname': 'Olive',
- 'lastname': 'Ranieri',
- 'dateofbirth': datetime.datetime(1985, 5, 12, 23, 14, 30),
- 'gender': 'FEMALE',
- 'vocation': 'ENGINEER'
- }
- {
- 'person_id': '6392529400',
- 'firstname': 'Elise',
- 'lastname': 'Smith',
- 'dateofbirth': datetime.datetime(1972, 1, 13, 9, 32, 7),
- 'vocation': 'ENGINEER'
- }
-
-To view the complete code for this tutorial, see the `Completed Filtered Subset App
-`__
-on GitHub.
\ No newline at end of file
diff --git a/source/aggregation/group-total.txt b/source/aggregation/group-total.txt
deleted file mode 100644
index 42f58640..00000000
--- a/source/aggregation/group-total.txt
+++ /dev/null
@@ -1,258 +0,0 @@
-.. _pymongo-aggregation-group-total:
-
-===============
-Group and Total
-===============
-
-.. contents:: On this page
- :local:
- :backlinks: none
- :depth: 2
- :class: singlecol
-
-.. facet::
- :name: genre
- :values: tutorial
-
-.. meta::
- :keywords: code example, python, analyze, aggregation
-
-Introduction
-------------
-
-In this tutorial, you can learn how to use {+driver-short+} to
-construct an aggregation pipeline, perform the
-aggregation on a collection, and print the results by completing and
-running a sample app. This aggregation performs the following operations:
-
-- Matches a subset of documents by a field value
-- Groups documents by common field values
-- Adds computed fields to each result document
-
-Aggregation Task Summary
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-This tutorial demonstrates how to group and analyze customer order data. The
-results show the list of customers who purchased items in 2020 and
-includes each customer's order history for 2020.
-
-This example uses one collection, ``orders``, which contains documents
-describing individual product orders. Since each order can correspond to
-only one customer, the order documents are grouped by the
-``customer_id`` field, which contains customer email addresses.
-
-Before You Get Started
-----------------------
-
-.. include:: /includes/aggregation-tutorial-intro.rst
-
-After you set up the app, access the ``orders`` collection by adding the
-following code to the application:
-
-.. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-coll
- :end-before: end-coll
- :dedent:
-
-Delete any existing data and insert sample data into
-the ``orders`` collection as shown in the following code. Select the :guilabel:`Synchronous`
-or :guilabel:`Asynchronous` tab to see the corresponding code:
-
-.. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-insert-orders
- :end-before: end-insert-orders
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/group-total-async.py
- :language: python
- :copyable: true
- :start-after: start-insert-orders
- :end-before: end-insert-orders
- :dedent:
-
-Tutorial
---------
-
-.. procedure::
- :style: connected
-
- .. step:: Add a match stage for orders in 2020
-
- First, add a :manual:`$match
- ` stage that matches
- orders placed in 2020:
-
- .. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-match
- :end-before: end-match
- :dedent:
-
- .. step:: Add a sort stage to sort by order date
-
- Next, add a :manual:`$sort
- ` stage to set an
- ascending sort on the ``orderdate`` field to surface the earliest
- 2020 purchase for each customer in the next stage:
-
- .. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-sort1
- :end-before: end-sort1
- :dedent:
-
- .. step:: Add a group stage to group by email address
-
- Add a :manual:`$group
- ` stage to group
- orders by the value of the ``customer_id`` field. In this
- stage, add aggregation operations that create the
- following fields in the result documents:
-
- - ``first_purchase_date``: the date of the customer's first purchase
- - ``total_value``: the total value of all the customer's purchases
- - ``total_orders``: the total number of the customer's purchases
- - ``orders``: the list of all the customer's purchases,
- including the date and value of each purchase
-
- .. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-group
- :end-before: end-group
- :dedent:
-
- .. step:: Add a sort stage to sort by first order date
-
- Next, add another :manual:`$sort
- ` stage to set an
- ascending sort on the ``first_purchase_date`` field:
-
- .. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-sort2
- :end-before: end-sort2
- :dedent:
-
- .. step:: Add a set stage to display the email address
-
- Add a :manual:`$set
- ` stage to recreate the
- ``customer_id`` field from the values in the ``_id`` field
- that were set during the ``$group`` stage:
-
- .. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-set
- :end-before: end-set
- :dedent:
-
- .. step:: Add an unset stage to remove unneeded fields
-
- Finally, add an :manual:`$unset
- ` stage. The
- ``$unset`` stage removes the ``_id`` field from the result
- documents:
-
- .. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-unset
- :end-before: end-unset
- :dedent:
-
- .. step:: Run the aggregation pipeline
-
- Add the following code to the end of your application to perform
- the aggregation on the ``orders`` collection. Select the :guilabel:`Synchronous`
- or :guilabel:`Asynchronous` tab to see the corresponding code:
-
- .. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/group-total.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/group-total-async.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- Finally, run the following command in your shell to start your
- application:
-
- .. code-block:: bash
-
- python3 agg_tutorial.py
-
- .. step:: Interpret results
-
- The aggregation returns the following summary of customers' orders
- from 2020:
-
- .. code-block:: javascript
- :copyable: false
-
- {
- 'first_purchase_date': datetime.datetime(2020, 1, 1, 8, 25, 37),
- 'total_value': 63,
- 'total_orders': 1,
- 'orders': [ { 'orderdate': datetime.datetime(2020, 1, 1, 8, 25, 37), 'value': 63 } ],
- 'customer_id': 'oranieri@warmmail.com'
- }
- {
- 'first_purchase_date': datetime.datetime(2020, 1, 13, 9, 32, 7),
- 'total_value': 436,
- 'total_orders': 4,
- 'orders': [
- { 'orderdate': datetime.datetime(2020, 1, 13, 9, 32, 7), 'value': 99 },
- { 'orderdate': datetime.datetime(2020, 5, 30, 8, 35, 52), 'value': 231 },
- { 'orderdate': datetime.datetime(2020, 10, 3, 13, 49, 44), 'value': 102 },
- { 'orderdate': datetime.datetime(2020, 12, 26, 8, 55, 46), 'value': 4 }
- ],
- 'customer_id': 'elise_smith@myemail.com'
- }
- {
- 'first_purchase_date': datetime.datetime(2020, 8, 18, 23, 4, 48),
- 'total_value': 191,
- 'total_orders': 2,
- 'orders': [
- { 'orderdate': datetime.datetime(2020, 8, 18, 23, 4, 48), 'value': 4 },
- { 'orderdate': datetime.datetime(2020, 11, 23, 22, 56, 53), 'value': 187 }
- ],
- 'customer_id': 'tj@wheresmyemail.com'
- }
-
- The result documents contain details from all the orders from
- a given customer, grouped by the customer's email address.
-
-To view the complete code for this tutorial, see the `Completed Group and Total App
-`__
-on GitHub.
diff --git a/source/aggregation/multi-field-join.txt b/source/aggregation/multi-field-join.txt
deleted file mode 100644
index 3d805851..00000000
--- a/source/aggregation/multi-field-join.txt
+++ /dev/null
@@ -1,302 +0,0 @@
-.. _pymongo-aggregation-multi-field:
-
-================
-Multi-Field Join
-================
-
-.. contents:: On this page
- :local:
- :backlinks: none
- :depth: 2
- :class: singlecol
-
-.. facet::
- :name: genre
- :values: tutorial
-
-.. meta::
- :keywords: code example, python, lookup, aggregation
-
-Introduction
-------------
-
-In this tutorial, you can learn how to use {+driver-short+} to
-construct an aggregation pipeline, perform the
-aggregation on a collection, and print the results by completing and
-running a sample app.
-
-This aggregation performs a multi-field join. A multi-field join occurs when there are
-multiple corresponding fields in the documents of two collections that you use to
-match documents together. The aggregation matches these documents on the
-field values and combines information from both into one document.
-
-.. tip:: One-to-many Joins
-
- A one-to-many join is a variety of a multi-field join. When you
- perform a one-to-many join, you select one field from a document that
- matches a field value in multiple documents on the other side of the
- join. To learn more about these data relationships,
- see the Wikipedia entries about :wikipedia:`One-to-many (data model)
- ` and
- :wikipedia:`Many-to-many (data model)
- `.
-
-Aggregation Task Summary
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-This tutorial demonstrates how to combine data from a collection that
-describes product information with another collection that describes
-customer orders. The results show a list of products ordered in 2020
-that also contains details about each order.
-
-This example uses two collections:
-
-- ``products``, which contains documents describing the products that
- a shop sells
-- ``orders``, which contains documents describing individual orders
- for products in a shop
-
-An order can only contain one product, so the aggregation uses a
-multi-field join to match a product document to documents representing orders of
-that product. The collections are joined by the ``name`` and
-``variation`` fields in documents in the ``products`` collection, corresponding
-to the ``product_name`` and ``product_variation`` fields in documents in
-the ``orders`` collection.
-
-Before You Get Started
-----------------------
-
-.. include:: /includes/aggregation-tutorial-intro.rst
-
-After you set up the app, access the ``products`` and ``orders``
-collections by adding the following code to the application:
-
-.. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-colls
- :end-before: end-colls
- :dedent:
-
-Delete any existing data and insert sample data into
-the ``products`` collection as shown in the following code. Select the :guilabel:`Synchronous`
-or :guilabel:`Asynchronous` tab to see the corresponding code:
-
-.. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-insert-products
- :end-before: end-insert-products
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/multi-field-join-async.py
- :language: python
- :copyable: true
- :start-after: start-insert-products
- :end-before: end-insert-products
- :dedent:
-
-Delete any existing data and insert sample data into
-the ``orders`` collection as shown in the following code:
-
-.. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-insert-orders
- :end-before: end-insert-orders
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/multi-field-join-async.py
- :language: python
- :copyable: true
- :start-after: start-insert-orders
- :end-before: end-insert-orders
- :dedent:
-
-Tutorial
---------
-
-.. procedure::
- :style: connected
-
- .. step:: Add a lookup stage to link the collections and import fields
-
- The first stage of the pipeline is a :manual:`$lookup
- ` stage to join the
- ``orders`` collection to the ``products`` collection by two
- fields in each collection. The lookup stage contains an
- embedded pipeline to configure the join.
-
- Within the embedded pipeline, add a :manual:`$match
- ` stage to match the
- values of two fields on each side of the join. Note that the following
- code uses aliases for the ``name`` and ``variation`` fields
- set when creating the ``$lookup`` stage:
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-embedded-pl-match1
- :end-before: end-embedded-pl-match1
- :dedent:
-
- Within the embedded pipeline, add another :manual:`$match
- ` stage to match
- orders placed in 2020:
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-embedded-pl-match2
- :end-before: end-embedded-pl-match2
- :dedent:
-
- Within the embedded pipeline, add an :manual:`$unset
- ` stage to remove
- unneeded fields from the ``orders`` collection side of the join:
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-embedded-pl-unset
- :end-before: end-embedded-pl-unset
- :dedent:
-
- After the embedded pipeline is completed, add the
- ``$lookup`` stage to the main aggregation pipeline.
- Configure this stage to store the processed lookup fields in
- an array field called ``orders``:
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-lookup
- :end-before: end-lookup
- :dedent:
-
- .. step:: Add a match stage for products ordered in 2020
-
- Next, add a :manual:`$match
- ` stage to only show
- products for which there is at least one order in 2020,
- based on the ``orders`` array calculated in the previous step:
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-match
- :end-before: end-match
- :dedent:
-
- .. step:: Add an unset stage to remove unneeded fields
-
- Finally, add an :manual:`$unset
- ` stage. The
- ``$unset`` stage removes the ``_id`` and ``description``
- fields from the result documents:
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-unset
- :end-before: end-unset
- :dedent:
-
- .. step:: Run the aggregation pipeline
-
- Add the following code to the end of your application to perform
- the aggregation on the ``products`` collection. Select the :guilabel:`Synchronous`
- or :guilabel:`Asynchronous` tab to see the corresponding code:
-
- .. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/multi-field-join.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/multi-field-join-async.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- Finally, run the following command in your shell to start your
- application:
-
- .. code-block:: bash
-
- python3 agg_tutorial.py
-
- .. step:: Interpret results
-
- The aggregated result contains two documents. The documents
- represent products for which there were orders placed in 2020.
- Each document contains an ``orders`` array field that lists details
- about each order for that product:
-
- .. code-block:: javascript
- :copyable: false
-
- {
- 'name': 'Asus Laptop',
- 'variation': 'Standard Display',
- 'category': 'ELECTRONICS',
- 'orders': [
- {
- 'customer_id': 'elise_smith@myemail.com',
- 'orderdate': datetime.datetime(2020, 5, 30, 8, 35, 52),
- 'value': 431.43
- },
- {
- 'customer_id': 'jjones@tepidmail.com',
- 'orderdate': datetime.datetime(2020, 12, 26, 8, 55, 46),
- 'value': 429.65
- }
- ]
- }
- {
- 'name': 'Morphy Richards Food Mixer',
- 'variation': 'Deluxe',
- 'category': 'KITCHENWARE',
- 'orders': [
- {
- 'customer_id': 'oranieri@warmmail.com',
- 'orderdate': datetime.datetime(2020, 1, 1, 8, 25, 37),
- 'value': 63.13
- }
- ]
- }
-
- The result documents contain details from documents in the
- ``orders`` collection and the ``products`` collection, joined by
- the product names and variations.
-
-To view the complete code for this tutorial, see the `Completed Multi-field Join App
-`__
-on GitHub.
diff --git a/source/aggregation/one-to-one-join.txt b/source/aggregation/one-to-one-join.txt
deleted file mode 100644
index 785a93b6..00000000
--- a/source/aggregation/one-to-one-join.txt
+++ /dev/null
@@ -1,273 +0,0 @@
-.. _pymongo-aggregation-one-to-one:
-
-===============
-One-to-One Join
-===============
-
-.. contents:: On this page
- :local:
- :backlinks: none
- :depth: 2
- :class: singlecol
-
-.. facet::
- :name: genre
- :values: tutorial
-
-.. meta::
- :keywords: code example, python, lookup, aggregation
-
-Introduction
-------------
-
-In this tutorial, you can learn how to use {+driver-short+} to
-construct an aggregation pipeline, perform the
-aggregation on a collection, and print the results by completing and
-running a sample app.
-
-This aggregation performs a one-to-one join. A one-to-one join occurs
-when a document in one collection has a field value that matches a
-single document in another collection that has the same field value. The
-aggregation matches these documents on the field value and combines
-information from both sources into one result.
-
-.. tip::
-
- A one-to-one join does not require the documents to have a
- one-to-one relationship. To learn more about this data relationship,
- see the Wikipedia entry about :wikipedia:`One-to-one (data model)
- `.
-
-Aggregation Task Summary
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-This tutorial demonstrates how to combine data from a collection that
-describes product information with another collection that describes
-customer orders. The results show a list of all orders placed in 2020 that
-includes the product details associated with each order.
-
-This example uses two collections:
-
-- ``orders``: contains documents describing individual orders
- for products in a shop
-- ``products``: contains documents describing the products that
- a shop sells
-
-An order can only contain one product, so the aggregation uses a
-one-to-one join to match an order document to the document for the
-product. The collections are joined by a field called ``product_id``
-that exists in documents in both collections.
-
-Before You Get Started
-----------------------
-
-.. include:: /includes/aggregation-tutorial-intro.rst
-
-After you set up the app, access the ``orders`` and ``products``
-collections by adding the following code to the application:
-
-.. literalinclude:: /includes/aggregation/one-to-one-join.py
- :language: python
- :copyable: true
- :start-after: start-colls
- :end-before: end-colls
- :dedent:
-
-Delete any existing data and insert sample data into
-the ``orders`` collection as shown in the following code. Select the :guilabel:`Synchronous`
-or :guilabel:`Asynchronous` tab to see the corresponding code:
-
-.. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/one-to-one-join.py
- :language: python
- :copyable: true
- :start-after: start-insert-orders
- :end-before: end-insert-orders
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/one-to-one-join-async.py
- :language: python
- :copyable: true
- :start-after: start-insert-orders
- :end-before: end-insert-orders
- :dedent:
-
-Delete any existing data and insert sample data into
-the ``products`` collection as shown in the following code:
-
-.. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/one-to-one-join.py
- :language: python
- :copyable: true
- :start-after: start-insert-products
- :end-before: end-insert-products
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/one-to-one-join-async.py
- :language: python
- :copyable: true
- :start-after: start-insert-products
- :end-before: end-insert-products
- :dedent:
-
-Tutorial
---------
-
-.. procedure::
- :style: connected
-
- .. step:: Add a match stage for orders in 2020
-
- Add a :manual:`$match
- ` stage that matches
- orders placed in 2020:
-
- .. literalinclude:: /includes/aggregation/one-to-one-join.py
- :language: python
- :copyable: true
- :start-after: start-match
- :end-before: end-match
- :dedent:
-
- .. step:: Add a lookup stage to link the collections
-
- Next, add a :manual:`$lookup
- ` stage. The
- ``$lookup`` stage joins the ``product_id`` field in the ``orders``
- collection to the ``id`` field in the ``products`` collection:
-
- .. literalinclude:: /includes/aggregation/one-to-one-join.py
- :language: python
- :copyable: true
- :start-after: start-lookup
- :end-before: end-lookup
- :dedent:
-
- .. step:: Add set stages to create new document fields
-
- Next, add two :manual:`$set `
- stages to the pipeline.
-
- The first ``$set`` stage sets the ``product_mapping`` field
- to the first element in the ``product_mapping`` object
- created in the previous ``$lookup`` stage.
-
- The second ``$set`` stage creates two new fields, ``product_name``
- and ``product_category``, from the values in the
- ``product_mapping`` object field:
-
- .. literalinclude:: /includes/aggregation/one-to-one-join.py
- :language: python
- :copyable: true
- :start-after: start-set
- :end-before: end-set
- :dedent:
-
- .. tip::
-
- Because this is a one-to-one join, the ``$lookup`` stage
- adds only one array element to the input document. The pipeline
- uses the :manual:`$first `
- operator to retrieve the data from this element.
-
- .. step:: Add an unset stage to remove unneeded fields
-
- Finally, add an :manual:`$unset
- ` stage. The
- ``$unset`` stage removes unnecessary fields from the document:
-
- .. literalinclude:: /includes/aggregation/one-to-one-join.py
- :language: python
- :copyable: true
- :start-after: start-unset
- :end-before: end-unset
- :dedent:
-
- .. step:: Run the aggregation pipeline
-
- Add the following code to the end of your application to perform
- the aggregation on the ``orders`` collection. Select the :guilabel:`Synchronous`
- or :guilabel:`Asynchronous` tab to see the corresponding code:
-
- .. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/one-to-one-join.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/one-to-one-join-async.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- Finally, run the following command in your shell to start your
- application:
-
- .. code-block:: bash
-
- python3 agg_tutorial.py
-
- .. step:: Interpret results
-
- The aggregated result contains three documents. The documents
- represent customer orders that occurred in 2020, with the
- ``product_name`` and ``product_category`` of the ordered product:
-
- .. code-block:: javascript
- :copyable: false
-
- {
- 'customer_id': 'elise_smith@myemail.com',
- 'orderdate': datetime.datetime(2020, 5, 30, 8, 35, 52),
- 'value': 431.43,
- 'product_name': 'Asus Laptop',
- 'product_category': 'ELECTRONICS'
- }
- {
- 'customer_id': 'oranieri@warmmail.com',
- 'orderdate': datetime.datetime(2020, 1, 1, 8, 25, 37),
- 'value': 63.13,
- 'product_name': 'Morphy Richardds Food Mixer',
- 'product_category': 'KITCHENWARE'
- }
- {
- 'customer_id': 'jjones@tepidmail.com',
- 'orderdate': datetime.datetime(2020, 12, 26, 8, 55, 46),
- 'value': 429.65,
- 'product_name': 'Asus Laptop',
- 'product_category': 'ELECTRONICS'
- }
-
- The result consists of documents that contain fields from
- documents in the ``orders`` collection and the ``products``
- collection, joined by matching the ``product_id`` field present in
- each original document.
-
-To view the complete code for this tutorial, see the `Completed One-to-one Join App
-`__
-on GitHub.
diff --git a/source/aggregation/unpack-arrays.txt b/source/aggregation/unpack-arrays.txt
deleted file mode 100644
index 1feee3ed..00000000
--- a/source/aggregation/unpack-arrays.txt
+++ /dev/null
@@ -1,239 +0,0 @@
-.. _pymongo-aggregation-arrays:
-
-=======================
-Unpack Arrays and Group
-=======================
-
-.. contents:: On this page
- :local:
- :backlinks: none
- :depth: 2
- :class: singlecol
-
-.. facet::
- :name: genre
- :values: tutorial
-
-.. meta::
- :keywords: code example, python, analyze, array
-
-Introduction
-------------
-
-In this tutorial, you can learn how to use {+driver-short+} to
-construct an aggregation pipeline, perform the
-aggregation on a collection, and print the results by completing and
-running a sample app. This aggregation performs the following operations:
-
-- Unwinds an array field into separate documents
-- Matches a subset of documents by a field value
-- Groups documents by common field values
-- Adds computed fields to each result document
-
-Aggregation Task Summary
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-This tutorial demonstrates how to create insights from customer order
-data. The results show the list of products ordered that cost more than
-$15, and each document contains the number of units sold and the total
-sale value for each product.
-
-This example uses one collection, ``orders``, which contains documents
-describing product orders. Since each order contains multiple products,
-the first step of the aggregation is unpacking the ``products`` array
-into individual product order documents.
-
-Before You Get Started
-----------------------
-
-.. include:: /includes/aggregation-tutorial-intro.rst
-
-After you set up the app, access the ``orders`` collection by adding the
-following code to the application:
-
-.. literalinclude:: /includes/aggregation/unpack-arrays.py
- :language: python
- :copyable: true
- :start-after: start-coll
- :end-before: end-coll
- :dedent:
-
-Delete any existing data and insert sample data into
-the ``orders`` collection as shown in the following code. Select the :guilabel:`Synchronous`
-or :guilabel:`Asynchronous` tab to see the corresponding code:
-
-.. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/unpack-arrays.py
- :language: python
- :copyable: true
- :start-after: start-insert-orders
- :end-before: end-insert-orders
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/unpack-arrays-async.py
- :language: python
- :copyable: true
- :start-after: start-insert-orders
- :end-before: end-insert-orders
- :dedent:
-
-Tutorial
---------
-
-.. procedure::
- :style: connected
-
- .. step:: Add an unwind stage to unpack the array of product orders
-
- First, add an :manual:`$unwind
- ` stage to separate the
- entries in the ``products`` array into individual documents:
-
- .. literalinclude:: /includes/aggregation/unpack-arrays.py
- :language: python
- :copyable: true
- :start-after: start-unwind
- :end-before: end-unwind
- :dedent:
-
- .. step:: Add a match stage for products that cost more than $15
-
- Next, add a :manual:`$match
- ` stage that matches
- products with a ``products.price`` value greater than ``15``:
-
- .. literalinclude:: /includes/aggregation/unpack-arrays.py
- :language: python
- :copyable: true
- :start-after: start-match
- :end-before: end-match
- :dedent:
-
- .. step:: Add a group stage to group by product type
-
- Add a :manual:`$group
- ` stage to group
- orders by the value of the ``prod_id`` field. In this
- stage, add aggregation operations that create the
- following fields in the result documents:
-
- - ``product``: the product name
- - ``total_value``: the total value of all the sales of the product
- - ``quantity``: the number of orders for the product
-
- .. literalinclude:: /includes/aggregation/unpack-arrays.py
- :language: python
- :copyable: true
- :start-after: start-group
- :end-before: end-group
- :dedent:
-
- .. step:: Add a set stage to display the product ID
-
- Add a :manual:`$set
- ` stage to recreate the
- ``product_id`` field from the values in the ``_id`` field
- that were set during the ``$group`` stage:
-
- .. literalinclude:: /includes/aggregation/unpack-arrays.py
- :language: python
- :copyable: true
- :start-after: start-set
- :end-before: end-set
- :dedent:
-
- .. step:: Add an unset stage to remove unneeded fields
-
- Finally, add an :manual:`$unset
- ` stage. The
- ``$unset`` stage removes the ``_id`` field from the result
- documents:
-
- .. literalinclude:: /includes/aggregation/unpack-arrays.py
- :language: python
- :copyable: true
- :start-after: start-unset
- :end-before: end-unset
- :dedent:
-
- .. step:: Run the aggregation pipeline
-
- Add the following code to the end of your application to perform
- the aggregation on the ``orders`` collection. Select the :guilabel:`Synchronous`
- or :guilabel:`Asynchronous` tab to see the corresponding code:
-
- .. tabs::
-
- .. tab:: Synchronous
- :tabid: sync
-
- .. literalinclude:: /includes/aggregation/unpack-arrays.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- .. tab:: Asynchronous
- :tabid: async
-
- .. literalinclude:: /includes/aggregation/unpack-arrays-async.py
- :language: python
- :copyable: true
- :start-after: start-run-agg
- :end-before: end-run-agg
- :dedent:
-
- Finally, run the following command in your shell to start your
- application:
-
- .. code-block:: bash
-
- python3 agg_tutorial.py
-
- .. step:: Interpret results
-
- The aggregation returns the following summary of customers' orders
- from 2020:
-
- .. code-block:: javascript
- :copyable: false
-
- {
- 'product': 'Asus Laptop',
- 'total_value': 860,
- 'quantity': 2,
- 'product_id': 'abc12345'
- }
- {
- 'product': 'Morphy Richards Food Mixer',
- 'total_value': 431,
- 'quantity': 1,
- 'product_id': 'pqr88223'
- }
- {
- 'product': 'Russell Hobbs Chrome Kettle',
- 'total_value': 16,
- 'quantity': 1,
- 'product_id': 'xyz11228'
- }
- {
- 'product': 'Karcher Hose Set',
- 'total_value': 66,
- 'quantity': 3,
- 'product_id': 'def45678'
- }
-
- The result documents contain details about the total value and
- quantity of orders for products that cost more than $15.
-
-To view the complete code for this tutorial, see the `Completed Unpack Arrays App
-`__
-on GitHub.
diff --git a/source/reference.txt b/source/reference.txt
index 4863c166..a171795b 100644
--- a/source/reference.txt
+++ b/source/reference.txt
@@ -17,8 +17,8 @@ Reference
To find information about versioning, upgrading your driver, and migrating to
the asynchronous driver, see the following pages:
- - :ref:`Release Notes `
- - :ref:`Compatibility `
- - :ref:`Upgrade Guides `
- - :ref:`Migrate to PyMongo Async `
- - :ref:`Previous Versions `
\ No newline at end of file
+- :ref:`Release Notes `
+- :ref:`Compatibility `
+- :ref:`Upgrade Guides `
+- :ref:`Migrate to PyMongo Async `
+- :ref:`Previous Versions `
\ No newline at end of file