From a1df67572ef269f8e764153dcd967b153d879441 Mon Sep 17 00:00:00 2001 From: norareidy Date: Tue, 6 Aug 2024 15:42:55 -0400 Subject: [PATCH 001/149] Add PR template --- source/.github/pull_request_template.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 source/.github/pull_request_template.md diff --git a/source/.github/pull_request_template.md b/source/.github/pull_request_template.md new file mode 100644 index 00000000..ea43ad96 --- /dev/null +++ b/source/.github/pull_request_template.md @@ -0,0 +1,14 @@ +# Pull Request Info + +[PR Reviewing Guidelines](https://github.com/mongodb/docs-rust/blob/master/REVIEWING.md) + +JIRA - +Staging - + +## Self-Review Checklist + +- [ ] Is this free of any warnings or errors in the RST? +- [ ] Did you run a spell-check? +- [ ] Did you run a grammar-check? +- [ ] Are all the links working? +- [ ] Are the [facets and meta keywords](https://wiki.corp.mongodb.com/display/DE/Docs+Taxonomy) accurate? From ef92914a3401a13e1ca35f173a34ea23c21cff7a Mon Sep 17 00:00:00 2001 From: norareidy Date: Tue, 6 Aug 2024 15:52:18 -0400 Subject: [PATCH 002/149] Scaffolding --- .../pull_request_template.md | 2 +- .github/workflows/check-autobuilder.yml | 13 ++++++ .../workflows/copy-compat-to-docs-shared.yml | 41 ++++++++++++++++++ .github/workflows/vale-tdbx.yml | 39 +++++++++++++++++ REVIEWING.md | 42 +++++++++++++++++++ 5 files changed, 136 insertions(+), 1 deletion(-) rename {source/.github => .github}/pull_request_template.md (82%) create mode 100644 .github/workflows/check-autobuilder.yml create mode 100644 .github/workflows/copy-compat-to-docs-shared.yml create mode 100644 .github/workflows/vale-tdbx.yml create mode 100644 REVIEWING.md diff --git a/source/.github/pull_request_template.md b/.github/pull_request_template.md similarity index 82% rename from source/.github/pull_request_template.md rename to .github/pull_request_template.md index ea43ad96..af6ae21e 100644 --- a/source/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,6 +1,6 @@ # Pull Request Info -[PR Reviewing Guidelines](https://github.com/mongodb/docs-rust/blob/master/REVIEWING.md) +[PR Reviewing Guidelines](https://github.com/mongodb/docs-php-library/blob/master/REVIEWING.md) JIRA - Staging - diff --git a/.github/workflows/check-autobuilder.yml b/.github/workflows/check-autobuilder.yml new file mode 100644 index 00000000..8495db96 --- /dev/null +++ b/.github/workflows/check-autobuilder.yml @@ -0,0 +1,13 @@ +name: Check Autobuilder for Errors + +on: + pull_request: + paths: + - "source/**" + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: cbush/snooty-autobuilder-check@main diff --git a/.github/workflows/copy-compat-to-docs-shared.yml b/.github/workflows/copy-compat-to-docs-shared.yml new file mode 100644 index 00000000..0ac439b3 --- /dev/null +++ b/.github/workflows/copy-compat-to-docs-shared.yml @@ -0,0 +1,41 @@ +name: Copy Files to docs-shared + +on: + workflow_dispatch: {} # use to manually trigger workflow + push: + branches: + - "master" + paths: + - "source/includes/mongodb-compatibility-table-php.rst" + - "source/includes/language-compatibility-table-php.rst" + +jobs: + copy-file: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Copy mongodb-compat table + uses: dmnemec/copy_file_to_another_repo_action@main + env: + API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} + with: + source_file: "source/includes/mongodb-compatibility-table-php.rst" + destination_repo: "10gen/docs-shared" + destination_folder: "dbx" + user_email: "docs-builder-bot@mongodb.com" + user_name: "docs-builder-bot" + commit_message: "Auto-import from docs-php-library" + + - name: Copy language-compat table + uses: dmnemec/copy_file_to_another_repo_action@main + env: + API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} + with: + source_file: "source/includes/language-compatibility-table-php.rst" + destination_repo: "10gen/docs-shared" + destination_folder: "dbx" + user_email: "docs-builder-bot@mongodb.com" + user_name: "docs-builder-bot" + commit_message: "Auto-import from docs-php-library" diff --git a/.github/workflows/vale-tdbx.yml b/.github/workflows/vale-tdbx.yml new file mode 100644 index 00000000..ca2a7348 --- /dev/null +++ b/.github/workflows/vale-tdbx.yml @@ -0,0 +1,39 @@ +name: vale-checks +on: + pull_request: + paths: + - "source/**" + +jobs: + vale: + name: TDBX Vale rules + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4 + + - id: files + uses: masesgroup/retrieve-changed-files@v2 + with: + format: 'csv' + + - name: checkout-latest-rules + uses: actions/checkout@v4 + with: + repository: mongodb/mongodb-vale-action + path: './tdbx-vale-rules' + token: ${{secrets.GITHUB_TOKEN}} + + - name: move-files-for-vale-action + run: | + cp tdbx-vale-rules/.vale.ini .vale.ini + mkdir -p .github/styles/ + cp -rf tdbx-vale-rules/.github/styles/ .github/ + + - name: run-vale + uses: errata-ai/vale-action@reviewdog + with: + reporter: github-pr-check + files: ${{steps.files.outputs.added_modified}} + fail_on_error: true + token: ${{secrets.GITHUB_TOKEN}} diff --git a/REVIEWING.md b/REVIEWING.md new file mode 100644 index 00000000..7357049a --- /dev/null +++ b/REVIEWING.md @@ -0,0 +1,42 @@ +# Pull Request Reviewing Guidelines for MongoDB PHP Library Documentation + +Contributions to the set of documents in this repository can receive reviews from one or both of the following types of reviews: + +1. A **copy review**, which focuses on information structure and wording; typically performed by a MongoDB Documentation Team member +2. A **technical review**, which addresses code snippets and the technical correctness of prose; typically performed by a MongoDB engineer. + +See the following sections for reviewer expectations for each type of pull request (PR) review: + +## Copy Review + +Review the structure, wording, and flow of the information in the PR, and correct it if necessary. + +### What to Review + +- Wording +- Page structure +- Technical content to the extent of the reviewer's understanding. +- Whether the PR fulfills the Acceptance Criteria described in the + linked JIRA ticket. + +### What Not to Review + +Nothing is completely off-limits to a copy review of a PR -- if you notice a technical issue, it's best to call it out early. +Copy reviewers should constrain their reviews to content within the scope of the JIRA ticket, or otherwise create PRs to address anything unrelated. + +## Technical Review + +Review the technical accuracy and completeness of a PR and correct it if necessary. + +### What to Review + +- Code snippets; ensure the code is idiomatic and that all technical claims are correct. e.g. ("To create a `Foo`, use the `Bar.createFoo()` method") +- Problematic explanations that could trip up users who try to follow the documentation. + +### What Not to Review + +While we welcome any recommendations on wording and structure, avoid blocking approval based on any copy edits. Please entrust the author to make the writing decisions based on style guidelines and team-specific writing conventions, and to create PRs to address anything they deem outside the technical review scope. + +- Wording of sentences, although corrections to technical claims are welcome +- Structure of the page +- Any unchanged lines outside the PR unless relevant to the ticket acceptance criteria. \ No newline at end of file From 42838af233471abe803eb933c63f8cbb3196a775 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Wed, 7 Aug 2024 10:56:50 -0400 Subject: [PATCH 003/149] DOCSP-41953: Create a deployment (#93) * DOCSP-41953: Create a deployment * toc * add troubleshoot file --- source/get-started.txt | 23 +++++++++++++ source/get-started/create-a-deployment.txt | 36 ++++++++++++++++++++ source/includes/get-started/troubleshoot.rst | 6 ++++ source/index.txt | 1 + 4 files changed, 66 insertions(+) create mode 100644 source/get-started.txt create mode 100644 source/get-started/create-a-deployment.txt create mode 100644 source/includes/get-started/troubleshoot.rst diff --git a/source/get-started.txt b/source/get-started.txt new file mode 100644 index 00000000..edd20aef --- /dev/null +++ b/source/get-started.txt @@ -0,0 +1,23 @@ +.. _php-get-started: + +================================ +Get Started with the PHP Library +================================ + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: tutorial + +.. meta:: + :description: Learn how to create an app to connect to MongoDB deployment by using the PHP library. + :keywords: quick start, tutorial, basics + +.. toctree:: + + /get-started/create-a-deployment/ \ No newline at end of file diff --git a/source/get-started/create-a-deployment.txt b/source/get-started/create-a-deployment.txt new file mode 100644 index 00000000..52c1203a --- /dev/null +++ b/source/get-started/create-a-deployment.txt @@ -0,0 +1,36 @@ +.. _php-create-deployment: + +=========================== +Create a MongoDB Deployment +=========================== + +.. facet:: + :name: genre + :values: tutorial + +.. meta:: + :keywords: cloud, uri, atlas + +You can create a free tier MongoDB deployment on MongoDB Atlas +to store and manage your data. MongoDB Atlas hosts and manages +your MongoDB database in the cloud. + +.. procedure:: + :style: connected + + .. step:: Create a free MongoDB deployment on Atlas + + Complete the :atlas:`Get Started with Atlas ` + guide to set up a new Atlas account and load sample data into a new free + tier MongoDB deployment. + + .. step:: Save your credentials + + After you create your database user, save that user's + username and password to a safe location for use in an upcoming step. + +After you complete these steps, you have a new free tier MongoDB +deployment on Atlas, database user credentials, and sample data loaded +into your database. + +.. include:: /includes/get-started/troubleshoot.rst \ No newline at end of file diff --git a/source/includes/get-started/troubleshoot.rst b/source/includes/get-started/troubleshoot.rst new file mode 100644 index 00000000..08d6e428 --- /dev/null +++ b/source/includes/get-started/troubleshoot.rst @@ -0,0 +1,6 @@ +.. note:: + + If you run into issues on this step, ask for help in the + :community-forum:`MongoDB Community Forums ` + or submit feedback by using the :guilabel:`Rate this page` + tab on the right or bottom right side of this page. \ No newline at end of file diff --git a/source/index.txt b/source/index.txt index 1c5c6e72..244f3eb2 100644 --- a/source/index.txt +++ b/source/index.txt @@ -11,6 +11,7 @@ MongoDB PHP Library :titlesonly: Installation + Get Started /tutorial /upgrade /reference From aab488d93150682dec342c2f036cd95adf634a1d Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Thu, 8 Aug 2024 13:37:10 -0400 Subject: [PATCH 004/149] DOCSP-41954: Create a connection string (#99) * DOCSP-41954: Create a connection string * edits * spacing --- .gitignore | 1 - source/get-started.txt | 3 +- .../create-a-connection-string.txt | 68 ++++++++++++++++++ source/get-started/create-a-deployment.txt | 2 +- .../atlas_connection_copy_string_php.png | Bin 0 -> 147154 bytes .../atlas_connection_select_cluster.png | Bin 0 -> 35481 bytes 6 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 source/get-started/create-a-connection-string.txt create mode 100644 source/includes/figures/atlas_connection_copy_string_php.png create mode 100644 source/includes/figures/atlas_connection_select_cluster.png diff --git a/.gitignore b/.gitignore index b42a4f24..85d69aa9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ build/* build *~ *giza.log -source/* backups/* diff --git a/source/get-started.txt b/source/get-started.txt index edd20aef..6641f3c3 100644 --- a/source/get-started.txt +++ b/source/get-started.txt @@ -20,4 +20,5 @@ Get Started with the PHP Library .. toctree:: - /get-started/create-a-deployment/ \ No newline at end of file + /get-started/create-a-deployment/ + /get-started/create-a-connection-string/ \ No newline at end of file diff --git a/source/get-started/create-a-connection-string.txt b/source/get-started/create-a-connection-string.txt new file mode 100644 index 00000000..52a096c4 --- /dev/null +++ b/source/get-started/create-a-connection-string.txt @@ -0,0 +1,68 @@ +.. _php-connection-string: + +========================== +Create a Connection String +========================== + +.. facet:: + :name: genre + :values: tutorial + +.. meta:: + :keywords: uri, atlas + +You can connect to your MongoDB deployment by providing a +**connection URI**, also called a *connection string*, which +instructs the driver on how to connect to a MongoDB deployment +and how to behave while connected. + +The connection string includes the hostname or IP address and +port of your deployment, the authentication mechanism, user credentials +when applicable, and connection options. + +.. TODO: + To connect to an instance or deployment not hosted on Atlas, see + :ref:`php-connection-targets`. + +.. procedure:: + :style: connected + + .. step:: Find your MongoDB Atlas Connection String + + To retrieve your connection string for the deployment that + you created in the :ref:`previous step `, + log in to your Atlas account and navigate to the + :guilabel:`Database` section and click the :guilabel:`Connect` button + for your new deployment. + + .. figure:: /includes/figures/atlas_connection_select_cluster.png + :alt: The connect button in the clusters section of the Atlas UI + + Then, select your user from the :guilabel:`Select database user` + selection menu. Select "PHP" from the :guilabel:`Driver` selection + menu and the version that best matches the version you installed + from the :guilabel:`Version` selection menu. + + Select the :guilabel:`String` tab in the :guilabel:`Add connection string into your application code` + step to view only the connection string. + + .. step:: Copy your Connection String + + Click the button on the right of the connection string to copy it + to your clipboard, as shown in the following screenshot: + + .. figure:: /includes/figures/atlas_connection_copy_string_php.png + :alt: The copy button next to the connection string in the Atlas UI + + .. step:: Update the Placeholders + + Paste this connection string into a file in your preferred text editor + and replace the ```` and ```` placeholders with + your database user's username and password. + + Save this file to a safe location for use in the next step. + +After completing these steps, you have a connection string that +corresponds to your Atlas cluster. + +.. include:: /includes/get-started/troubleshoot.rst \ No newline at end of file diff --git a/source/get-started/create-a-deployment.txt b/source/get-started/create-a-deployment.txt index 52c1203a..fa72db96 100644 --- a/source/get-started/create-a-deployment.txt +++ b/source/get-started/create-a-deployment.txt @@ -9,7 +9,7 @@ Create a MongoDB Deployment :values: tutorial .. meta:: - :keywords: cloud, uri, atlas + :keywords: cloud, host, atlas You can create a free tier MongoDB deployment on MongoDB Atlas to store and manage your data. MongoDB Atlas hosts and manages diff --git a/source/includes/figures/atlas_connection_copy_string_php.png b/source/includes/figures/atlas_connection_copy_string_php.png new file mode 100644 index 0000000000000000000000000000000000000000..b15ef37ab8446e19a77663664b3cb6270238e676 GIT binary patch literal 147154 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

euO@9j23=s9ABT4o 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 z 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

4N?~)Xc)h9V|#8Xnx^ocodOvO(h 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 literal 0 HcmV?d00001 From 2419c76a1d26e682b00e26e8e345fbea48a0ed52 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Thu, 8 Aug 2024 16:51:04 -0400 Subject: [PATCH 005/149] DOCSP-42388: Next steps (#101) --- source/get-started.txt | 3 ++- source/get-started/next-steps.txt | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 source/get-started/next-steps.txt diff --git a/source/get-started.txt b/source/get-started.txt index 6641f3c3..54399028 100644 --- a/source/get-started.txt +++ b/source/get-started.txt @@ -21,4 +21,5 @@ Get Started with the PHP Library .. toctree:: /get-started/create-a-deployment/ - /get-started/create-a-connection-string/ \ No newline at end of file + /get-started/create-a-connection-string/ + /get-started/next-steps/ \ No newline at end of file diff --git a/source/get-started/next-steps.txt b/source/get-started/next-steps.txt new file mode 100644 index 00000000..3be97ed2 --- /dev/null +++ b/source/get-started/next-steps.txt @@ -0,0 +1,23 @@ +.. _php-next-steps: + +========== +Next Steps +========== + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: learn more + +Congratulations on completing the quick start tutorial! + +In this tutorial, you created a PHP application that +connects to a MongoDB deployment hosted on MongoDB Atlas +and retrieves a document that matches a query. + +.. TODO: + Learn more about the {+php-library+} from the following resources: + - Learn how to perform read operations in the :ref:`` section. + - Learn how to perform write operations in the :ref:`` section. \ No newline at end of file From e9945332044431b93ea0e26d846477fb974003ff Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 19 Aug 2024 10:26:35 -0400 Subject: [PATCH 006/149] DOCSP-41975: Retrieve data (#102) * DOCSP-41975: Retrieve data * fixes * quotes * code fix * JS feedback * JT feedback * code format * fix * JT feedback 2 * edit --- snooty.toml | 1 + source/includes/read/retrieve.php | 40 +++++ source/index.txt | 1 + source/read.txt | 11 ++ source/read/retrieve.txt | 244 ++++++++++++++++++++++++++++++ 5 files changed, 297 insertions(+) create mode 100644 source/includes/read/retrieve.php create mode 100644 source/read.txt create mode 100644 source/read/retrieve.txt diff --git a/snooty.toml b/snooty.toml index a08a8d41..507f09d6 100644 --- a/snooty.toml +++ b/snooty.toml @@ -24,3 +24,4 @@ php-library = "MongoDB PHP Library" [constants] php-library = "MongoDB PHP Library" +api = "https://www.mongodb.com/docs/php-library/current/reference" diff --git a/source/includes/read/retrieve.php b/source/includes/read/retrieve.php new file mode 100644 index 00000000..a6ee53b5 --- /dev/null +++ b/source/includes/read/retrieve.php @@ -0,0 +1,40 @@ +sample_training; +$collection = $db->companies; +// end-db-coll + +// Finds one document with a "name" value of "LinkedIn" +// start-find-one +$document = $collection->findOne(['name' => 'LinkedIn']); +echo json_encode($document) . "\n"; +// end-find-one + +// Finds documents with a "founded_year" value of 1970 +// start-find-many +$results = $collection->find(['founded_year' => 1970]); +// end-find-many + +// Prints documents with a "founded_year" value of 1970 +// start-cursor +foreach ($results as $doc) { + echo json_encode($doc) . "\n"; +} +// end-cursor + +// Finds and prints up to 5 documents with a "number_of_employees" value of 1000 +// start-modify +$results = $collection->find( + ['number_of_employees' => 1000], + ['limit' => 5] +); + +foreach ($results as $doc) { + echo json_encode($doc) . "\n"; +} +// end-modify diff --git a/source/index.txt b/source/index.txt index 244f3eb2..26734024 100644 --- a/source/index.txt +++ b/source/index.txt @@ -12,6 +12,7 @@ MongoDB PHP Library Installation Get Started + /read /tutorial /upgrade /reference diff --git a/source/read.txt b/source/read.txt new file mode 100644 index 00000000..eb974b7f --- /dev/null +++ b/source/read.txt @@ -0,0 +1,11 @@ +.. _php-read: + +====================== +Read Data from MongoDB +====================== + +.. toctree:: + :titlesonly: + :maxdepth: 1 + + /read/retrieve \ No newline at end of file diff --git a/source/read/retrieve.txt b/source/read/retrieve.txt new file mode 100644 index 00000000..2820e32c --- /dev/null +++ b/source/read/retrieve.txt @@ -0,0 +1,244 @@ +.. _php-retrieve: + +============= +Retrieve Data +============= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code examples, read, query, cursor + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to retrieve +data from a MongoDB collection by using **read operations**. You can call the +``MongoDB\Collection::find()`` or ``MongoDB\Collection::findOne()`` method +on a collection to retrieve documents that match a set of criteria. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``companies`` collection in the ``sample_training`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following values to your ``db`` and ``collection`` variables: + +.. literalinclude:: /includes/read/retrieve.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +.. _php-retrieve-find: + +Find Documents +-------------- + +The {+php-library+} includes two methods for retrieving documents from a collection: +``MongoDB\Collection::findOne()`` and ``MongoDB\Collection::find()``. These methods +take a **query filter** and return one or more matching documents. A query filter +specifies the search criteria that the driver uses to retrieve documents in your query. + +.. TODO: To learn more about query filters, see :ref:`php-specify-query`. + +.. _php-retrieve-find-one: + +Find One Document +~~~~~~~~~~~~~~~~~ + +To find a single document in a collection, call the ``MongoDB\Collection::findOne()`` +method and pass a query filter that specifies the criteria of the document you want to find. + +The ``findOne()`` method returns an ``array``, ``object``, or ``null`` value. If the +query filter matches a document, the method returns an ``array|object`` instance containing +the document. The return type depends on the value of the ``typeMap`` option. If the query +filter does not match any documents, the method returns ``null``. + +.. tip:: + + To learn more about ``findOne()`` options, such as ``typeMap``, see the :ref:`php-retrieve-modify` + section of this guide. + +If the query filter matches more than one document, the ``findOne()`` method returns the *first* +matching document from the retrieved results. + +The following example uses the ``findOne()`` method to find the first document in which +the ``name`` field has the value ``'LinkedIn'``: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/retrieve.php + :start-after: start-find-one + :end-before: end-find-one + :language: php + :dedent: + + .. output:: + + {"_id":{"$oid":"..."},"name":"LinkedIn","permalink":"linkedin","crunchbase_url": + "http:\/\/www.crunchbase.com\/company\/linkedin","homepage_url":"http:\/\/linkedin.com", + ... } + +.. tip:: Sort Order + + The ``findOne()`` method returns the first document in + :manual:`natural order ` + on disk if no sort criteria is specified. + +.. _php-retrieve-find-multiple: + +Find Multiple Documents +~~~~~~~~~~~~~~~~~~~~~~~ + +To find multiple documents in a collection, pass a query filter to the +``MongoDB\Collection::find()`` method that specifies the criteria of the +documents you want to retrieve. + +The following example uses the ``find()`` method to find all documents in which +the ``founded_year`` field has the value ``1970``: + +.. literalinclude:: /includes/read/retrieve.php + :language: php + :dedent: + :start-after: start-find-many + :end-before: end-find-many + +The ``find()`` method returns an instance of ``MongoDB\Driver\Cursor``, which you can +iterate over to see the matching documents. A cursor is a mechanism that allows an +application to iterate over database results while holding only a subset of them in +memory at a given time. Cursors are useful when your ``find()`` method returns a large +amount of documents. + +You can iterate over the documents in a cursor by using a ``foreach`` loop, as shown in +the following example: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/retrieve.php + :start-after: start-cursor + :end-before: end-cursor + :language: php + :dedent: + + .. output:: + + {"_id":{"$oid":"..."},"name":"Mitsubishi Motors","permalink":"mitsubishi-motors", + "crunchbase_url":"http:\/\/www.crunchbase.com\/company\/mitsubishi-motors", + ... } + + {"_id":{"$oid":"..."},"name":"Western Digital","permalink":"western-digital", + "crunchbase_url":"http:\/\/www.crunchbase.com\/company\/western-digital", + ... } + + {"_id":{"$oid":"..."},"name":"Celarayn","permalink":"celarayn","crunchbase_url": + "http:\/\/www.crunchbase.com\/company\/celarayn", + ... } + +.. note:: Find All Documents + + To find all documents in a collection, pass an empty filter + to the ``find()`` method: + + .. code-block:: php + + $cursor = $collection->find([]); + +.. _php-retrieve-modify: + +Modify Find Behavior +~~~~~~~~~~~~~~~~~~~~ + +You can modify the behavior of the ``MongoDB\Collection::find()`` and +``MongoDB\Collection::findOne()`` methods by passing an array that specifies +option values as a parameter. The following table describes some options +you can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``batchSize`` + - | The number of documents to return per batch. The default value is ``101``. + | **Type**: ``integer`` + + * - ``collation`` + - | The collation to use for the operation. The default value is the collation + specified for the collection. + | **Type**: ``array|object`` + + * - ``comment`` + - | The comment to attach to the operation. + | **Type**: any BSON type + + * - ``cursorType`` + - | The type of cursor to use for the operation. The default value is + ``MongoDB\Operation\Find::NON_TAILABLE``. + | **Type**: ``MongoDB\Operation\Find`` + + * - ``limit`` + - | The maximum number of documents the operation can return. + | **Type**: ``integer`` + + * - ``skip`` + - | The number of documents to skip before returning results. + | **Type**: ``integer`` + + * - ``sort`` + - | The order in which the operation returns matching documents. + | **Type**: ``array|object`` + + * - ``typeMap`` + - | The type map to apply to cursors, which determines how BSON documents + are converted to PHP values. The default value is the collection's type map. + | **Type**: ``array`` + +The following example uses the ``find()`` method to find all documents in which +the ``number_of_employees`` field has the value ``1000``. The example uses the +``limit`` option to return a maximum of ``5`` results: + +.. literalinclude:: /includes/read/retrieve.php + :language: php + :emphasize-lines: 3 + :start-after: start-modify + :end-before: end-modify + +For a full list of options, see the API documentation for the +`findOne() <{+api+}/method/MongoDBCollection-findOne/#parameters>`__ and +`find() <{+api+}/method/MongoDBCollection-find/#parameters>`__ parameters. + +.. _php-retrieve-additional-information: + +Additional Information +---------------------- + +.. TODO: + To learn more about query filters, see :ref:`php-specify-query`. + For runnable code examples of retrieving documents with the {+php-library+}, + see :ref:`php-read`. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ +- `find() <{+api+}/method/MongoDBCollection-find/>`__ \ No newline at end of file From 110405139213cf5a3a254b3c0bde606506c76ce1 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Wed, 21 Aug 2024 13:24:56 -0400 Subject: [PATCH 007/149] DOCSP-41952: Download and Install (#92) * DOCSP-41952: Download and Install * edits * toc, fixes * AS feedback * AS feedback 2 * typo * JT feedback --- snooty.toml | 1 + source/get-started.txt | 24 ++++- source/get-started/download-and-install.txt | 102 ++++++++++++++++++++ source/index.txt | 3 +- source/tutorial/install-php-library.txt | 99 ------------------- 5 files changed, 126 insertions(+), 103 deletions(-) create mode 100644 source/get-started/download-and-install.txt delete mode 100644 source/tutorial/install-php-library.txt diff --git a/snooty.toml b/snooty.toml index 507f09d6..c877a988 100644 --- a/snooty.toml +++ b/snooty.toml @@ -17,6 +17,7 @@ toc_landing_pages = [ "/reference/class/MongoDBModelCollectionInfo", "/reference/class/MongoDBModelDatabaseInfo", "/reference/class/MongoDBModelIndexInfo", + "/get-started", ] [substitutions] diff --git a/source/get-started.txt b/source/get-started.txt index 54399028..ac7e9788 100644 --- a/source/get-started.txt +++ b/source/get-started.txt @@ -13,13 +13,33 @@ Get Started with the PHP Library .. facet:: :name: genre :values: tutorial - + .. meta:: :description: Learn how to create an app to connect to MongoDB deployment by using the PHP library. :keywords: quick start, tutorial, basics .. toctree:: + /get-started/download-and-install/ /get-started/create-a-deployment/ /get-started/create-a-connection-string/ - /get-started/next-steps/ \ No newline at end of file + /get-started/next-steps/ + +Overview +-------- + +The {+php-library+} is a high-level abstraction for the MongoDB PHP extension, which +you can use to connect to MongoDB and interact with data stored in your deployment. +This guide shows you how to create an application that uses the {+php-library+} to +connect to a MongoDB cluster hosted on MongoDB Atlas and query data in your cluster. + +.. tip:: + + MongoDB Atlas is a fully managed cloud database service that hosts your MongoDB + deployments. You can create your own free (no credit card required) MongoDB Atlas + deployment by following the steps in this guide. + +Follow this guide to connect a sample PHP application to a MongoDB Atlas +deployment. If you prefer to connect to MongoDB using a different driver or +programming language, see our :driver:`list of official drivers <>`. + diff --git a/source/get-started/download-and-install.txt b/source/get-started/download-and-install.txt new file mode 100644 index 00000000..356830fc --- /dev/null +++ b/source/get-started/download-and-install.txt @@ -0,0 +1,102 @@ +.. _php-download-and-install: + +==================== +Download and Install +==================== + +.. facet:: + :name: genre + :values: tutorial + +.. meta:: + :keywords: setup, composer, installation, code example + +.. procedure:: + :style: connected + + .. step:: Install dependencies + + Before you begin developing, ensure that you have the following + dependencies installed on your local machine: + + - `PHP `__ version 7.4 or later + - `Composer `__ version 2.0 or later + + .. step:: Install the MongoDB PHP extension + + Run the following command to install the ``mongodb`` PHP extension: + + .. code-block:: bash + + sudo pecl install mongodb + + .. step:: Update your PHP configuration file + + To enable the ``mongodb`` extension in your PHP configuration file, add the + following line to the top of your ``php.ini`` file: + + .. code-block:: none + + extension=mongodb.so + + .. tip:: + + You can locate your ``php.ini`` file by running the following command + in your shell: + + .. code-block:: bash + + php --ini + + .. step:: Create a project directory + + From your root directory, run the following command in your shell to create + a directory called ``php-quickstart`` for this project: + + .. code-block:: bash + + mkdir php-quickstart + + Select the tab corresponding to your operating system and run the following commands + to create a ``quickstart.php`` application file in the ``php-quickstart`` directory: + + .. tabs:: + + .. tab:: macOS / Linux + :tabid: create-file-mac-linux + + .. code-block:: bash + + cd php-quickstart + touch quickstart.php + + .. tab:: Windows + :tabid: create-file-windows + + .. code-block:: bash + + cd php-quickstart + type nul > quickstart.php + + .. step:: Install the {+php-library+} + + To install the {+php-library+}, run the following command in your ``php-quickstart`` + directory: + + .. code-block:: bash + + composer require mongodb/mongodb + + After installing the library, include Composer's ``autoload.php`` file by adding the + following code to the top of your ``quickstart.php`` file: + + .. code-block:: php + + Get Started /read /tutorial @@ -39,7 +38,7 @@ New to the PHP Library? If you have some experience with MongoDB but are new to the PHP library, the following pages should help you get started: -- :doc:`/tutorial/install-php-library` +- :ref:`php-download-and-install` - :doc:`/tutorial/connecting` diff --git a/source/tutorial/install-php-library.txt b/source/tutorial/install-php-library.txt deleted file mode 100644 index 913a945e..00000000 --- a/source/tutorial/install-php-library.txt +++ /dev/null @@ -1,99 +0,0 @@ -========================= -Install the |php-library| -========================= - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -The |php-library| is a high-level abstraction for the -:php:`mongodb extension `. This page will briefly explain how to -install both the ``mongodb`` extension and the |php-library|. - -Installing the Extension ------------------------- - -Linux, Unix, and macOS users can either -:php:`install the extension with PECL ` -(recommended) or -:php:`manually compile from source `. -The following command may be used to install the extension with PECL: - -.. code-block:: sh - - sudo pecl install mongodb - -.. note:: - - If the build process for either installation method fails to find a TLS - library, check that the development packages (e.g. ``libssl-dev``) and - `pkg-config `_ are both installed. - -Once the extension is installed, add the following line to your ``php.ini`` -file: - -.. code-block:: ini - - extension=mongodb.so - -Windows users can download precompiled binaries of the extension from its -`GitHub releases `__. -After downloading the appropriate archive for your PHP environment, extract the -``php_mongodb.dll`` file to PHP's extension directory and add the following line -to your ``php.ini`` file: - -.. code-block:: ini - - extension=php_mongodb.dll - -See :php:`Installing the MongoDB PHP Driver on Windows ` -for additional information. - -Installing the Library ----------------------- - -Using Composer -~~~~~~~~~~~~~~ - -The preferred method of installing the |php-library| is with -`Composer `_ by running the following command from -your project root: - -.. code-block:: sh - - composer require mongodb/mongodb - -Once you have installed the library, ensure that your application includes -Composer's autoloader as in the following example: - -.. code-block:: php - - `_ for more -information about setting up autoloading. - -Manual Installation Without Composer -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -While not recommended, you may also manually install the library using a source -archive attached to the -`GitHub releases `__. -When installing the library without Composer, you must ensure that all library -classes *and* functions are loaded for your application: - -#. If you are using a `PSR-4 `_ autoloader, - map the top-level ``MongoDB\`` namespace to the ``src/`` directory. If you - are not using an autoloader, manually require _all_ class files found - recursively within the ``src/`` directory. - -#. Regardless of whether you are using an autoloader, manually require the - ``src/functions.php`` file. This is necessary because PHP does not support - autoloading for functions. From f4d7b49d2d2a6e28fe4fa61091d2563fd4905bdb Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Wed, 21 Aug 2024 13:25:17 -0400 Subject: [PATCH 008/149] DOCSP-41976: Projection guide (#104) * DOCSP-41976: Projection guide * edits * fixes * code edits, output * JS feedback * JT feedback --- snooty.toml | 1 + source/includes/read/project.php | 59 ++++++++++ source/includes/read/retrieve.php | 3 +- source/read.txt | 4 +- source/read/project.txt | 172 ++++++++++++++++++++++++++++++ source/read/retrieve.txt | 2 +- 6 files changed, 237 insertions(+), 4 deletions(-) create mode 100644 source/includes/read/project.php create mode 100644 source/read/project.txt diff --git a/snooty.toml b/snooty.toml index c877a988..c97fe021 100644 --- a/snooty.toml +++ b/snooty.toml @@ -25,4 +25,5 @@ php-library = "MongoDB PHP Library" [constants] php-library = "MongoDB PHP Library" +mdb-server = "MongoDB Server" api = "https://www.mongodb.com/docs/php-library/current/reference" diff --git a/source/includes/read/project.php b/source/includes/read/project.php new file mode 100644 index 00000000..1e7c42f3 --- /dev/null +++ b/source/includes/read/project.php @@ -0,0 +1,59 @@ +sample_restaurants->restaurants; +// end-db-coll + +// Retrieves documents matching the "name" field query and projects their "name", "cuisine", and "borough" values +// start-project-include +$options = [ + 'projection' => [ + 'name' => 1, + 'cuisine' => 1, + 'borough' => 1, + ], +]; + +$cursor = $collection->find(['name' => 'Emerald Pub'], $options); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-project-include + +// Retrieves documents matching the "name" field query +// and projects their "name", "cuisine", and "borough" values while excluding the "_id" values +// start-project-include-without-id +$options = [ + 'projection' => [ + '_id' => 0, + 'name' => 1, + 'cuisine' => 1, + 'borough' => 1, + ], +]; + +$cursor = $collection->find(['name' => 'Emerald Pub'], $options); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-project-include-without-id + +// Retrieves documents matching the "name" field query and excludes their "grades" and "address" values when printing +// start-project-exclude +$options = [ + 'projection' => [ + 'grades' => 0, + 'address' => 0, + ], +]; + +$cursor = $collection->find(['name' => 'Emerald Pub'], $options); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-project-exclude diff --git a/source/includes/read/retrieve.php b/source/includes/read/retrieve.php index a6ee53b5..fbd64a0d 100644 --- a/source/includes/read/retrieve.php +++ b/source/includes/read/retrieve.php @@ -5,8 +5,7 @@ $client = new MongoDB\Client($uri); // start-db-coll -$db = $client->sample_training; -$collection = $db->companies; +$collection = $client->sample_training->companies; // end-db-coll // Finds one document with a "name" value of "LinkedIn" diff --git a/source/read.txt b/source/read.txt index eb974b7f..a5c58482 100644 --- a/source/read.txt +++ b/source/read.txt @@ -8,4 +8,6 @@ Read Data from MongoDB :titlesonly: :maxdepth: 1 - /read/retrieve \ No newline at end of file + /read/retrieve + /read/project + diff --git a/source/read/project.txt b/source/read/project.txt new file mode 100644 index 00000000..7b568185 --- /dev/null +++ b/source/read/project.txt @@ -0,0 +1,172 @@ +.. _php-project: + +======================== +Specify Fields To Return +======================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: read, filter, project, select + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to specify which fields +to return from a read operation by using a **projection**. A projection is a document +that specifies which fields MongoDB returns from a query. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``collection`` variable: + +.. literalinclude:: /includes/read/project.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +Projection Types +---------------- + +You can use a projection to specify which fields to include in a return +document, or to specify which fields to exclude. You cannot combine inclusion and +exclusion statements in a single projection, unless you are excluding the +``_id`` field. + +Specify Fields to Include +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To specify the fields to include in the result, pass an options array to the +``MongoDB\Collection::findOne()`` or ``MongoDB\Collection::find()`` method that +sets the ``projection`` option. Use the following syntax to set this option: + +.. code-block:: php + + $options = [ + 'projection' => [ + '' => 1, + ], + ]; + +The following example creates an options array and sets the ``projection`` option +to return only the ``name``, ``cuisine``, and ``borough`` fields of matching documents. +It then calls the ``find()`` method to find all restaurants in which the ``name`` field +value is ``'Emerald Pub'``, passing the options array as a parameter to ``find()``: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/project.php + :start-after: start-project-include + :end-before: end-project-include + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},"borough":"Manhattan","cuisine":"American","name":"Emerald Pub"} + {"_id":{"$oid":"..."},"borough":"Queens","cuisine":"American","name":"Emerald Pub"} + +When you use a projection to specify fields to include in the return +document, the ``_id`` field is also included by default. All other fields are +implicitly excluded. To remove the ``_id`` field from the return +document, you must :ref:`explicitly exclude it `. + +.. _php-project-remove-id: + +Exclude the ``_id`` Field +~~~~~~~~~~~~~~~~~~~~~~~~~ + +When specifying fields to include, you can also exclude the ``_id`` field from +the returned document. + +The following example performs the same query as the preceding example but +excludes the ``_id`` field from the projection: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/project.php + :start-after: start-project-include-without-id + :end-before: end-project-include-without-id + :language: php + :dedent: + + .. output:: + :visible: false + + {"borough":"Manhattan","cuisine":"American","name":"Emerald Pub"} + {"borough":"Queens","cuisine":"American","name":"Emerald Pub"} + +Specify Fields to Exclude +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To specify the fields to exclude from the result, pass an options array to the +``MongoDB\Collection::findOne()`` or ``MongoDB\Collection::find()`` method that +sets the ``projection`` option. Use the following syntax to set this option: + +.. code-block:: php + + $options = [ + 'projection' => [ + '' => 0, + ], + ]; + +The following example creates an options array and sets the ``projection`` option +to exclude the ``grades`` and ``address`` fields of matching documents. +It then calls the ``find()`` method to find all restaurants in which the ``name`` +field value is ``'Emerald Pub'``, passing the options array as a parameter to +``find()``: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/project.php + :start-after: start-project-exclude + :end-before: end-project-exclude + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},"borough":"Manhattan","cuisine":"American", + "name":"Emerald Pub","restaurant_id":"40367329"} + {"_id":{"$oid":"..."},"borough":"Queens","cuisine":"American", + "name":"Emerald Pub","restaurant_id":"40668598"} + +When you use a projection to specify which fields to exclude, +any unspecified fields are implicitly included in the return document. + +Additional Information +---------------------- + +To learn more about projections, see the :manual:`Project Fields +` guide in the {+mdb-server+} manual. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ +- `MongoDB\\Collection::find() <{+api+}/method/MongoDBCollection-find/>`__ \ No newline at end of file diff --git a/source/read/retrieve.txt b/source/read/retrieve.txt index 2820e32c..cd1507db 100644 --- a/source/read/retrieve.txt +++ b/source/read/retrieve.txt @@ -31,7 +31,7 @@ Sample Data The examples in this guide use the ``companies`` collection in the ``sample_training`` database from the :atlas:`Atlas sample datasets `. To access this collection from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster -and assign the following values to your ``db`` and ``collection`` variables: +and assign the following value to your ``collection`` variable: .. literalinclude:: /includes/read/retrieve.php :language: php From 38870287fefe320a67a1b216ee64b39e0c4da245 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Tue, 27 Aug 2024 10:16:24 -0400 Subject: [PATCH 009/149] DOCSP-41955: Connect to MongoDB (#100) * DOCSP-41955: Connect to MongoDB * edits * edit * RR feedback * typo * code edit --- source/get-started.txt | 1 + source/get-started/connect-to-mongodb.txt | 69 ++++++++++++++++++++++ source/includes/get-started/quickstart.php | 17 ++++++ 3 files changed, 87 insertions(+) create mode 100644 source/get-started/connect-to-mongodb.txt create mode 100644 source/includes/get-started/quickstart.php diff --git a/source/get-started.txt b/source/get-started.txt index ac7e9788..d9a61995 100644 --- a/source/get-started.txt +++ b/source/get-started.txt @@ -23,6 +23,7 @@ Get Started with the PHP Library /get-started/download-and-install/ /get-started/create-a-deployment/ /get-started/create-a-connection-string/ + /get-started/connect-to-mongodb/ /get-started/next-steps/ Overview diff --git a/source/get-started/connect-to-mongodb.txt b/source/get-started/connect-to-mongodb.txt new file mode 100644 index 00000000..7492fe25 --- /dev/null +++ b/source/get-started/connect-to-mongodb.txt @@ -0,0 +1,69 @@ +.. _php-connect-to-mongodb: + +================== +Connect to MongoDB +================== + +.. facet:: + :name: genre + :values: tutorial + +.. meta:: + :keywords: test connection, runnable, code example + +After retrieving the connection string for your MongoDB Atlas deployment, +you can connect to the deployment from your PHP application and query +the Atlas sample datasets. + +.. procedure:: + :style: connected + + .. step:: Edit your PHP application file + + Copy and paste the following code into the ``quickstart.php`` file, which queries + the ``movies`` collection in the ``sample_mflix`` database: + + .. literalinclude:: /includes/get-started/quickstart.php + :language: php + :dedent: + + .. step:: Assign the connection string + + Replace the ```` placeholder with the + connection string that you copied from the :ref:`php-connection-string` + step of this guide. + + .. step:: Run your PHP application + + In your project directory, run the following shell command to start the application: + + .. code-block:: bash + + php quickstart.php + + The command line output contains details about the retrieved movie + document: + + .. code-block:: none + :copyable: false + + { + "_id": { + "$oid": "..." + }, + ... + "rated": "R", + "metacritic": 80, + "title": "The Shawshank Redemption", + ... + } + + If you encounter an error or see no output, ensure that you specified the + proper connection string in the ``quickstart.php`` file and that you loaded the + sample data. + +After you complete these steps, you have a PHP application that +connects to your MongoDB deployment, runs a query on the sample +data, and returns a matching document. + +.. include:: /includes/get-started/troubleshoot.rst diff --git a/source/includes/get-started/quickstart.php b/source/includes/get-started/quickstart.php new file mode 100644 index 00000000..d62dd83e --- /dev/null +++ b/source/includes/get-started/quickstart.php @@ -0,0 +1,17 @@ +'); +$collection = $client->sample_mflix->movies; + +$filter = ['title' => 'The Shawshank Redemption']; +$result = $collection->findOne($filter); + +if ($result) { + echo json_encode($result, JSON_PRETTY_PRINT); +} else { + echo "Document not found"; +} From cbead213e62f628d5888ece5307d2b29737e26fb Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Tue, 27 Aug 2024 10:19:45 -0400 Subject: [PATCH 010/149] DOCSP-41974: Specify a query (#103) * DOCSP-41974: Specify a query * edits * output * fix * snooty.toml * RR feedback * code edits --- source/includes/read/specify-queries.php | 108 +++++++++ source/read.txt | 3 +- source/read/specify-a-query.txt | 265 +++++++++++++++++++++++ 3 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 source/includes/read/specify-queries.php create mode 100644 source/read/specify-a-query.txt diff --git a/source/includes/read/specify-queries.php b/source/includes/read/specify-queries.php new file mode 100644 index 00000000..3e3c07cb --- /dev/null +++ b/source/includes/read/specify-queries.php @@ -0,0 +1,108 @@ +"; +$client = new Client($uri); +$collection = $client->db->fruits; + +// Inserts documents representing fruits +$fruits = [ + [ + '_id' => 1, + 'name' => 'apples', + 'qty' => 5, + 'rating' => 3, + 'color' => 'red', + 'type' => ['fuji', 'honeycrisp'] + ], + [ + '_id' => 2, + 'name' => 'bananas', + 'qty' => 7, + 'rating' => 4, + 'color' => 'yellow', + 'type' => ['cavendish'] + ], + [ + '_id' => 3, + 'name' => 'oranges', + 'qty' => 6, + 'rating' => 2, + 'type' => ['naval', 'mandarin'] + ], + [ + '_id' => 4, + 'name' => 'pineapples', + 'qty' => 3, + 'rating' => 5, + 'color' => 'yellow' + ] +]; + +$result = $collection->insertMany($fruits); +// end-setup + +// Retrieves documents in which the "color" value is "yellow" +// start-find-exact +$cursor = $collection->find(['color' => 'yellow']); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-find-exact + +// Retrieves all documents in the collection +// start-find-all +$cursor = $collection->find([]); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-find-all + +// Retrieves and prints documents in which the "rating" value is greater than 2 +// start-find-comparison +$cursor = $collection->find(['rating' => ['$gt' => 2]]); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-find-comparison + +// Retrieves and prints documents that match one or both query filters +// start-find-logical +$cursor = $collection->find([ + '$or' => [ + ['qty' => ['$gt' => 5]], + ['color' => 'yellow'] + ] +]); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-find-logical + +// Retrieves and prints documents in which the "type" array has 2 elements +// start-find-array +$cursor = $collection->find(['type' => ['$size' => 2]]); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-find-array + +// Retrieves and prints documents that have a "color" field +// start-find-element +$cursor = $collection->find(['color' => ['$exists' => true]]); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-find-element + +// Retrieves and prints documents in which the "name" value has at least two consecutive "p" characters +// start-find-evaluation +$cursor = $collection->find(['name' => ['$regex' => 'p{2,}']]); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-find-evaluation diff --git a/source/read.txt b/source/read.txt index a5c58482..5cc0e838 100644 --- a/source/read.txt +++ b/source/read.txt @@ -7,7 +7,8 @@ Read Data from MongoDB .. toctree:: :titlesonly: :maxdepth: 1 - + /read/retrieve + /read/specify-a-query /read/project diff --git a/source/read/specify-a-query.txt b/source/read/specify-a-query.txt new file mode 100644 index 00000000..9e38c2f6 --- /dev/null +++ b/source/read/specify-a-query.txt @@ -0,0 +1,265 @@ +.. _php-specify-query: + +=============== +Specify a Query +=============== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: expressions, operations, read, write, filter + +Overview +-------- + +In this guide, you can learn how to specify a query by using the {+php-library+}. + +You can refine the set of documents that a query returns by creating a +**query filter**. A query filter is an expression that specifies the search +criteria that MongoDB uses to match documents in a read or write operation. +In a query filter, you can prompt the driver to search for documents that have +an exact match to your query, or you can compose query filters to express more +complex matching criteria. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide run operations on the ``fruits`` collection, +which contains documents representing fruits. The following +code example shows how to create a database and collection, then +insert the sample documents into your collection: + +.. literalinclude:: /includes/read/specify-queries.php + :start-after: start-setup + :end-before: end-setup + :language: php + :dedent: + :copyable: + +Exact Match +----------- + +Literal value queries return documents that have an exact match to your query filter. + +The following example specifies a query filter as a parameter to the ``MongoDB\Collection::find()`` +method. The code returns all documents in which the value of the ``color`` field +is ``'yellow'``: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/specify-queries.php + :start-after: start-find-exact + :end-before: end-find-exact + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":2,"name":"bananas","qty":7,"rating":4,"color":"yellow","type":["cavendish"]} + {"_id":4,"name":"pineapples","qty":3,"rating":5,"color":"yellow"} + +.. tip:: Find All Documents + + To find all documents in a collection, call the ``find()`` method and pass it an + empty query filter. The following example finds all documents in a + collection: + + .. literalinclude:: /includes/read/specify-queries.php + :start-after: start-find-all + :end-before: end-find-all + :language: php + :dedent: + :copyable: + +Comparison Operators +-------------------- + +Comparison operators evaluate a document field value against a specified value +in your query filter. The following list defines common comparison operators: + +- ``$gt``: Greater than +- ``$lte``: Less than or Equal +- ``$ne``: Not equal + +To view a full list of comparison operators, see the :manual:`Comparison Query Operators +` guide in the {+mdb-server+} manual. + +The following example specifies a comparison operator in a query filter as a +parameter to the ``MongoDB\Collection::find()`` method. The code returns all documents +in which the value of the ``rating`` field is greater than ``2``: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/specify-queries.php + :start-after: start-find-comparison + :end-before: end-find-comparison + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":1,"name":"apples","qty":5,"rating":3,"color":"red","type":["fuji","honeycrisp"]} + {"_id":2,"name":"bananas","qty":7,"rating":4,"color":"yellow","type":["cavendish"]} + {"_id":4,"name":"pineapples","qty":3,"rating":5,"color":"yellow"} + +Logical Operators +----------------- + +Logical operators match documents by using logic applied to the results of two or +more sets of expressions. The following list describes each logical operator: + +- ``$and``: Returns all documents that match the conditions of *all* clauses +- ``$or``: Returns all documents that match the conditions of *one* clause +- ``$nor``: Returns all documents that *do not* match the conditions of any clause +- ``$not``: Returns all documents that *do not* match the expression + +To learn more about logical operators, see the :manual:`Logical Query Operators +` guide in the {+mdb-server+} manual. + +The following example specifies a logical operator in a query filter as a +parameter to the ``MongoDB\Collection::find()`` method. The code returns all documents +in which the ``qty`` field value is greater than ``5`` **or** the ``color`` field +value is ``'yellow'``: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/specify-queries.php + :start-after: start-find-logical + :end-before: end-find-logical + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":2,"name":"bananas","qty":7,"rating":4,"color":"yellow","type":["cavendish"]} + {"_id":3,"name":"oranges","qty":6,"rating":2,"type":["naval","mandarin"]} + {"_id":4,"name":"pineapples","qty":3,"rating":5,"color":"yellow"} + +Array Operators +--------------- + +Array operators match documents based on the value or quantity of elements in an +array field. The following list describes the available array operators: + +- ``$all``: Returns documents with arrays that contain all elements in the query +- ``$elemMatch``: Returns documents if an element in their array field matches all conditions in the query +- ``$size``: Returns all documents with arrays of a specified size + +To learn more about array operators, see the :manual:`Array Query Operators +` guide in the {+mdb-server+} manual. + +The following example specifies an array operator in a query filter as a +parameter to the ``MongoDB\Collection::find()`` method. The code returns all +documents in which the ``type`` array field contains ``2`` elements: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/specify-queries.php + :start-after: start-find-array + :end-before: end-find-array + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":1,"name":"apples","qty":5,"rating":3,"color":"red","type":["fuji","honeycrisp"]} + {"_id":3,"name":"oranges","qty":6,"rating":2,"type":["naval","mandarin"]} + +Element Operators +----------------- + +Element operators query data based on the presence or type of a field. + +To learn more about element operators, see the :manual:`Element Query Operators +` guide in the {+mdb-server+} manual. + +The following example specifies an element operator in a query filter as a +parameter to the ``MongoDB\Collection::find()`` method. The code returns all +documents that have a ``color`` field: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/specify-queries.php + :start-after: start-find-element + :end-before: end-find-element + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":1,"name":"apples","qty":5,"rating":3,"color":"red","type":["fuji","honeycrisp"]} + {"_id":2,"name":"bananas","qty":7,"rating":4,"color":"yellow","type":["cavendish"]} + {"_id":4,"name":"pineapples","qty":3,"rating":5,"color":"yellow"} + +Evaluation Operators +-------------------- + +Evaluation operators return data based on evaluations of either individual +fields or the entire collection's documents. + +The following list describes common evaluation operators: + +- ``$text``: Performs a text search on the documents +- ``$regex``: Returns documents that match a specified regular expression +- ``$mod``: Performs a modulo operation on the value of a field and + returns documents where the remainder is a specified value + +To view a full list of evaluation operators, see the :manual:`Evaluation Query Operators +` guide in the {+mdb-server+} manual. + +The following example specifies an evaluation operator in a query filter as a +parameter to the ``MongoDB\Collection::find()`` method. The code uses a regular +expression to return all documents in which the ``name`` field value has at least +two consecutive ``'p'`` characters: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/specify-queries.php + :start-after: start-find-evaluation + :end-before: end-find-evaluation + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":1,"name":"apples","qty":5,"rating":3,"color":"red","type":["fuji","honeycrisp"]} + {"_id":4,"name":"pineapples","qty":3,"rating":5,"color":"yellow"} + +Additional Information +---------------------- + +To learn more about querying documents, see the :manual:`Query Documents +` guide in the {+mdb-server+} manual. + +.. TODO: + To learn more about retrieving documents with the {+php-library+}, see the + :ref:`php-retrieve` guide. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::find() <{+api+}/method/MongoDBCollection-find/>`__ +- `MongoDB\\Collection::insertMany() <{+api+}/method/MongoDBCollection-insertMany/>`__ \ No newline at end of file From 474fc1f55c483d465870db96b69ff0d9df279652 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Tue, 27 Aug 2024 10:30:44 -0400 Subject: [PATCH 011/149] DOCSP-41977: Specify documents to return (#105) * DOCSP-41977: Specify documents to return * edits * code output * toc * MM feedback, code edits * edit * JT feedback * edit * test * MM feedback 2 --- source/includes/read/limit-skip-sort.php | 76 ++++++ source/read.txt | 4 +- source/read/specify-documents-to-return.txt | 275 ++++++++++++++++++++ 3 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 source/includes/read/limit-skip-sort.php create mode 100644 source/read/specify-documents-to-return.txt diff --git a/source/includes/read/limit-skip-sort.php b/source/includes/read/limit-skip-sort.php new file mode 100644 index 00000000..3ab8a16f --- /dev/null +++ b/source/includes/read/limit-skip-sort.php @@ -0,0 +1,76 @@ +sample_restaurants->restaurants; +// end-db-coll + +// Retrieves 5 documents that have a "cuisine" value of "Italian" +// start-limit +$cursor = $collection->find( + ['cuisine' => 'Italian'], + ['limit' => 5] +); + +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-limit + +// Retrieves documents with a "cuisine" value of "Italian" and sorts in ascending "name" order +// start-sort +$cursor = $collection->find( + ['cuisine' => 'Italian'], + ['sort' => ['name' => 1]] +); + +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-sort + +// Retrieves documents with a "borough" value of "Manhattan" but skips the first 10 results +// start-skip +$cursor = $collection->find( + ['borough' => 'Manhattan'], + ['skip' => 10] +); + +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-skip + +// Retrieves 5 documents with a "cuisine" value of "Italian", skips the first 10 results, +// and sorts by ascending "name" order +// start-limit-sort-skip +$options = [ + 'sort' => ['name' => 1], + 'limit' => 5, + 'skip' => 10, +]; + +$cursor = $collection->find(['cuisine' => 'Italian'], $options); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-limit-sort-skip + +// Returns documents with a "cuisine" value of "Hawaiian" as arrays +// start-return-type +$options = [ + 'typeMap' => [ + 'root' => 'array', + 'document' => 'array' + ] +]; + +$cursor = $collection->find(['cuisine' => 'Hawaiian'], $options); +foreach ($cursor as $doc) { + print_r($doc) . PHP_EOL; +} +// end-return-type diff --git a/source/read.txt b/source/read.txt index 5cc0e838..a3f245ca 100644 --- a/source/read.txt +++ b/source/read.txt @@ -9,6 +9,6 @@ Read Data from MongoDB :maxdepth: 1 /read/retrieve + /read/specify-documents-to-return /read/specify-a-query - /read/project - + /read/project \ No newline at end of file diff --git a/source/read/specify-documents-to-return.txt b/source/read/specify-documents-to-return.txt new file mode 100644 index 00000000..4497569f --- /dev/null +++ b/source/read/specify-documents-to-return.txt @@ -0,0 +1,275 @@ +.. _php-specify-documents-to-return: + +=========================== +Specify Documents to Return +=========================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: read, paginate, pagination, order, code example + +Overview +-------- + +In this guide, you can learn how to specify which documents and which types to return +from a read operation by passing the following options to the ``MongoDB\Collection::find()`` +or ``MongoDB\Collection::findOne()`` method: + +- :ref:`limit `: Specifies the maximum number of documents + to return from a query +- :ref:`sort `: Specifies the sort order for the returned documents +- :ref:`skip `: Specifies the number of documents to skip before + returning query results +- :ref:`typeMap `: Converts the returned documents to a specified data + type + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``collection`` variable: + +.. literalinclude:: /includes/read/limit-skip-sort.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +.. _php-return-documents-limit: + +Limit +----- + +To specify the maximum number of documents returned from a read operation, create +an array that sets the ``limit`` option and pass the array as a parameter to the +``MongoDB\Collection::find()`` method. + +The following example finds all restaurants that have a ``cuisine`` field value +of ``'Italian'`` and limits the results to ``5`` documents: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/limit-skip-sort.php + :start-after: start-limit + :end-before: end-limit + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},...,"name":"Isle Of Capri Resturant","restaurant_id":"40364373"} + {"_id":{"$oid":"..."},...,"name":"Marchis Restaurant","restaurant_id":"40364668"} + {"_id":{"$oid":"..."},...,"name":"Crystal Room","restaurant_id":"40365013"} + {"_id":{"$oid":"..."},...,"name":"Forlinis Restaurant","restaurant_id":"40365098"} + {"_id":{"$oid":"..."},...,"name":"Angelo Of Mulberry St.","restaurant_id":"40365293"} + +.. tip:: + + The preceding example returns the first five documents matched by the query + according to their :manual:`natural order ` + in the database. The following section describes how to return the documents + in a specified order. + +.. _php-return-documents-sort: + +Sort +---- + +To return documents in a specified order, create an array that sets the ``sort`` +option. When setting this option, include the field to sort the results by and +the sort direction. A value of ``1`` sorts values from lowest to highest, and +a value of ``-1`` sorts them from highest to lowest. Then, pass the array as a +parameter to the ``MongoDB\Collection::find()`` or ``MongoDB\Collection::findOne()`` +method. + +The following example returns all documents that have a ``cuisine`` value of ``'Italian'``, +sorted in ascending order of ``name`` field values: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/limit-skip-sort.php + :start-after: start-sort + :end-before: end-sort + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},...,"name":"44 Sw Ristorante & Bar","restaurant_id":"40698807"} + {"_id":{"$oid":"..."},...,"name":"900 Park","restaurant_id":"41707964"} + {"_id":{"$oid":"..."},...,"name":"A Voce","restaurant_id":"41434084"} + ... + {"_id":{"$oid":"..."},...,"name":"Zucchero E Pomodori","restaurant_id":"41189590" } + +.. _php-return-documents-skip: + +Skip +---- + +To skip a specified number of documents before returning your query results, create +an array that sets the ``skip`` option and pass the array as a parameter to the +``MongoDB\Collection::find()`` or ``MongoDB\Collection::findOne()`` method. + +The following example returns all documents that have a ``borough`` field value +of ``'Manhattan'`` and skips the first ``10`` documents: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/limit-skip-sort.php + :start-after: start-skip + :end-before: end-skip + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},...,"name":"Cafe Metro","restaurant_id":"40363298"} + {"_id":{"$oid":"..."},...,"name":"Lexler Deli","restaurant_id":"40363426"} + {"_id":{"$oid":"..."},...,"name":"Domino'S Pizza","restaurant_id":"40363644"} + ... + +.. _php-return-documents-combine: + +Combine Limit, Sort, and Skip +----------------------------- + +You can set the ``limit``, ``sort``, and ``skip`` options in a single +options array and pass the array as a parameter to the read operation. +This allows you to set a maximum number of sorted documents to return, +skipping a specified number of documents before returning. + +The following example returns ``5`` documents that have a ``cuisine`` value of +``'Italian'``. The results are sorted in ascending order by ``name`` field value, +skipping the first ``10`` documents: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/limit-skip-sort.php + :start-after: start-limit-sort-skip + :end-before: end-limit-sort-skip + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},...,"name":"Acqua","restaurant_id":"40871070"} + {"_id":{"$oid":"..."},...,"name":"Acqua Restaurant","restaurant_id":"41591488"} + {"_id":{"$oid":"..."},...,"name":"Acqua Santa","restaurant_id":"40735858"} + {"_id":{"$oid":"..."},...,"name":"Acquista Trattoria","restaurant_id":"40813992"} + {"_id":{"$oid":"..."},...,"name":"Acquolina Catering","restaurant_id":"41381423"} + +.. note:: + + The order in which you call these methods doesn't change the documents + that are returned. The {+php-library+} automatically reorders the calls to + perform the sort operation first, the skip operation next, and then the limit + operation. + +.. _php-return-documents-type: + +Specify Return Type +------------------- + +To customize the data type of documents returned by a read operation, you can pass the +``typeMap`` option in an array parameter. + +By default, methods called on a ``MongoDB\Client``, ``MongoDB\Database``, or ``MongoDB\Collection`` +instance use the following type map: + +.. code-block:: php + + [ + 'array' => 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ] + +This default type map performs the following conversions: + +- Arrays to ``MongoDB\Model\BSONArray`` objects +- Top-level and embedded BSON documents to ``MongoDB\Model\BSONDocument`` objects + +In a custom type map, you can specify conversions to any type that implements +``MongoDB\BSON\Unserializable``, as well as the ``array``, ``stdClass``, and ``object`` +types. + +Example +~~~~~~~ + +The following example returns all documents that have a ``cuisine`` value of ``'Hawaiian'`` +and specifies the ``typeMap`` option to convert the documents to array values: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/limit-skip-sort.php + :start-after: start-return-type + :end-before: end-return-type + :language: php + :dedent: + + .. output:: + :visible: false + + Array + ( + [_id] => MongoDB\BSON\ObjectId Object + ( + [oid] => ... + ) + + [address] => Array + ( + ... + ) + + [borough] => Manhattan + [cuisine] => Hawaiian + [grades] => Array + ( + ... + + ) + + [name] => Makana + [restaurant_id] => 41509012 + ) + ... + +Additional Information +---------------------- + +For more information about retrieving documents, see the :ref:`php-retrieve` guide. + +For more information about specifying a query, see the :ref:`php-specify-query` guide. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ +- `MongoDB\\Collection::find() <{+api+}/method/MongoDBCollection-find/>`__ From ad5b51143d76646ffeb9c6409ad93a41ead8fe06 Mon Sep 17 00:00:00 2001 From: Mike Woofter <108414937+mongoKart@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:08:48 -0500 Subject: [PATCH 012/149] DOCSP-41957 - Mongo Client (#106) Co-authored-by: Rea Rustagi <85902999+rustagir@users.noreply.github.com> --- snooty.toml | 3 +- source/connect/client.txt | 105 +++++++++++++++++++++++ source/includes/connect/client.php | 3 + source/reference/class/MongoDBClient.txt | 4 +- 4 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 source/connect/client.txt create mode 100644 source/includes/connect/client.php diff --git a/snooty.toml b/snooty.toml index c97fe021..28b89f14 100644 --- a/snooty.toml +++ b/snooty.toml @@ -25,5 +25,6 @@ php-library = "MongoDB PHP Library" [constants] php-library = "MongoDB PHP Library" +driver-short = "PHP library" mdb-server = "MongoDB Server" -api = "https://www.mongodb.com/docs/php-library/current/reference" +api = "https://www.mongodb.com/docs/php-library/current/reference" \ No newline at end of file diff --git a/source/connect/client.txt b/source/connect/client.txt new file mode 100644 index 00000000..421f6fa2 --- /dev/null +++ b/source/connect/client.txt @@ -0,0 +1,105 @@ +.. _php-client: + +======================= +Create a MongoDB Client +======================= + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: connection string, URI, server, Atlas, settings + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +To connect to a MongoDB deployment, you must create the following items: + +- **Connection URI**, also known as a *connection string*, which tells the {+driver-short+} + which MongoDB deployment to connect to. +- **MongoDB\\Client** object, which creates the connection to the MongoDB deployment + and lets you perform operations on it. + +You can also set options within either or both of these components to +customize the way that the {+driver-short+} behaves +while connected to MongoDB. + +This guide describes the components of a connection string and shows how to +use a ``MongoDB\Client`` object to connect to a MongoDB deployment. + +.. _php-connection-uri: + +Connection URI +-------------- + +A standard connection string includes the following components: + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Component + - Description + + * - ``mongodb://`` + + - Required. A prefix that identifies this as a string in the + standard connection format. + + * - ``db_username:db_password`` + + - Optional. Authentication credentials. If you include these, the client + authenticates the user against the database specified in ``authSource``. + For more information about the ``authSource`` connection option, see + :ref:`php-auth`. + + * - ``host[:port]`` + + - Required. The host and optional port number where MongoDB is running. If you don't + include the port number, the driver uses the default port, ``27017``. + + * - ``/defaultauthdb`` + + - Optional. The authentication database to use if the + connection string includes ``db_username:db_password@`` + authentication credentials but not the ``authSource`` option. If you don't include + this component, the client authenticates the user against the ``admin`` database. + + * - ``?`` + + - Optional. A query string that specifies connection-specific + options as ``=`` pairs. See + :ref:`php-connection-options` for a full description of + these options. + +To learn more about connection strings, see +:manual:`Connection Strings ` in the +Server manual. + +Create a MongoDB\Client +----------------------- + +To create a connection to MongoDB, pass your connection string when constructing +an instance of the ``MongoDB\Client`` class. + +In the following example, the library uses a sample connection URI to connect to a MongoDB +deployment on port ``27017`` of ``localhost``: + +.. literalinclude:: /includes/connect/client.php + :language: php + :copyable: true + +API Documentation +----------------- + +To learn more about creating a ``MongoDB\Client`` object in the {+driver-short+}, +see the following API documentation: + +- :ref:`MongoDB\Client ` \ No newline at end of file diff --git a/source/includes/connect/client.php b/source/includes/connect/client.php new file mode 100644 index 00000000..48d40f4e --- /dev/null +++ b/source/includes/connect/client.php @@ -0,0 +1,3 @@ + Date: Wed, 28 Aug 2024 09:11:25 -0500 Subject: [PATCH 013/149] DOCSP-41960 - TLS (#114) --- snooty.toml | 4 +- source/connect/tls.txt | 268 ++++++++++++++++++ source/includes/connect/ca-dir.php | 11 + source/includes/connect/ca-file-tabs.rst | 23 ++ source/includes/connect/client-cert-tabs.rst | 23 ++ source/includes/connect/crl-file.php | 11 + source/includes/connect/crl-tabs.rst | 23 ++ .../connect/disable-cert-validation-tabs.rst | 23 ++ .../disable-host-verification-tabs.rst | 23 ++ source/includes/connect/insecure-tls-tabs.rst | 23 ++ source/includes/connect/key-file-password.rst | 24 ++ source/includes/connect/ocsp-tabs.rst | 23 ++ source/includes/connect/tls-tabs.rst | 22 ++ 13 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 source/connect/tls.txt create mode 100644 source/includes/connect/ca-dir.php create mode 100644 source/includes/connect/ca-file-tabs.rst create mode 100644 source/includes/connect/client-cert-tabs.rst create mode 100644 source/includes/connect/crl-file.php create mode 100644 source/includes/connect/crl-tabs.rst create mode 100644 source/includes/connect/disable-cert-validation-tabs.rst create mode 100644 source/includes/connect/disable-host-verification-tabs.rst create mode 100644 source/includes/connect/insecure-tls-tabs.rst create mode 100644 source/includes/connect/key-file-password.rst create mode 100644 source/includes/connect/ocsp-tabs.rst create mode 100644 source/includes/connect/tls-tabs.rst diff --git a/snooty.toml b/snooty.toml index 28b89f14..e30bbbc3 100644 --- a/snooty.toml +++ b/snooty.toml @@ -24,7 +24,9 @@ toc_landing_pages = [ php-library = "MongoDB PHP Library" [constants] + php-library = "MongoDB PHP Library" driver-short = "PHP library" mdb-server = "MongoDB Server" -api = "https://www.mongodb.com/docs/php-library/current/reference" \ No newline at end of file +driver-short = "PHP library" +api = "https://www.mongodb.com/docs/php-library/current/reference" diff --git a/source/connect/tls.txt b/source/connect/tls.txt new file mode 100644 index 00000000..f5e6fe23 --- /dev/null +++ b/source/connect/tls.txt @@ -0,0 +1,268 @@ +.. _php-tls: + +======================================== +Configure Transport Layer Security (TLS) +======================================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: security, authentication, transport layer security, encrypt + +Overview +-------- + +In this guide, you can learn how to use the :wikipedia:`TLS ` +protocol to secure your connection to a MongoDB deployment. + +When you enable TLS for a connection, the {+driver-short+} performs the following actions: + +- Uses TLS to connect to the MongoDB deployment +- Verifies the deployment's certificate +- Ensures that the certificate certifies the deployment + +To learn how to configure your MongoDB deployment for TLS, see the +:manual:`TLS configuration guide ` in the +{+mdb-server+} manual. + +.. note:: + + This page assumes prior knowledge of TLS/SSL and access to valid certificates. + A full description of TLS/SSL, PKI (Public Key Infrastructure) certificates, and + Certificate Authorities (CAs) is beyond the scope of this documentation. + +.. tip:: + + The {+driver-short+} delegates most TLS behavior to the MongoDB C Driver. + For information about how the C driver handles TLS, including configuration steps + and expected behavior, see + `Configuring TLS `__ + in the C driver Documentation. + +.. _php-enable-tls: + +Enable TLS +---------- + +To enable TLS for the connection to your MongoDB deployment, set the ``tls`` connection +option to ``true``. You can do this in two ways: by using the ``uriOptions`` parameter +of the ``MongoDB\Client`` constructor or through a parameter in your connection string. + +.. include:: /includes/connect/tls-tabs.rst + +.. tip:: + + If your connection string includes the ``+srv`` modification, which specifies the + SRV connection format, TLS is enabled on your connection by default. + + To learn more about the SRV connection format, see + :manual:`SRV Connection Format ` + in the {+mdb-server+} documentation. + +.. _php-specify-ca-file: + +Specify a CA File +------------------ + +During the TLS handshake, the MongoDB deployment presents a certificate key file to your +application to establish its identity. Usually, a deployment's certificate has been +signed by a well-known CA (certificate authority), and your application relies on this CA +to validate the certificate. + +During testing, however, you might want to act as your own CA. +In this case, you must instruct the {+driver-short+} to +use your CA certificates instead of ones signed by another CA. + +To do so, use the ``tlsCAFile`` connection option to specify the path to a ``.pem`` file +containing the root certificate chain. +You can do this in two ways: by using the ``uriOptions`` parameter +of the ``MongoDB\Client`` constructor or through a parameter in your connection string. + +.. include:: /includes/connect/ca-file-tabs.rst + +.. _php-specify-ca-directory: + +Specify a CA Directory +~~~~~~~~~~~~~~~~~~~~~~ + +If you are using OpenSSL or LibreSSL (``libtls``) for TLS support, you can also use +the ``ca_dir`` option to instruct +the {+driver-short+} to search for a CA file within a directory. The driver searches this +directory if it doesn't find a CA file at the path specified in the ``tlsCAFile`` option. + +The following code example shows how to use the ``driverOptions`` parameter to specify the +``ca_dir`` option: + +.. literalinclude:: /includes/connect/ca-dir.php + :language: php + :copyable: true + +.. tip:: + + This option corresponds to the OpenSSL + `SSL_CTX_load_verify_locations `__ + parameter and + the LibreSSL `tls_config_set_ca_path `__ + parameter. + +.. _php-certificate-revocation: + +Check Certificate Revocation +---------------------------- + +When an X.509 certificate is no longer trustworthy—for example, if its private key +has been compromised—the CA revokes the certificate. The {+driver-short+} includes two ways +to check whether a server's certificate has been revoked. + +.. _php-disable-ocsp: + +OCSP +~~~~ + +The Online Certificate Status Protocol (OCSP) process varies depending on the version of +{+mdb-server+} you're connecting to: + +- **MongoDB v4.4 or later:** The server staples a + time-stamped OCSP response to its certificate. The {+driver-short+} validates the certificate + against the OCSP response. If the CA has revoked the certificate, or if the OCSP response + is otherwise invalid, the TLS handshake fails. +- **MongoDB v4.3 or earlier:** The server supplies an OCSP endpoint, which the {+driver-short+} + contacts directly. The {+driver-short+} then validates the certificate against the OCSP + response. If the CA hasn't revoked the certificate, the TLS handshake continues, even if + the OCSP response is invalid or malformed. + +To stop the {+driver-short+} from contacting the OCSP endpoint, set the +``tlsDisableOCSPEndpointCheck`` connection option to ``true``. +You can do this in two ways: by passing an argument to the +``MongoDB\Client`` constructor or through a parameter in your connection string. + +.. include:: /includes/connect/ocsp-tabs.rst + +.. note:: + + Even if the ``tlsDisableOCSPEndpointCheck`` option is set to ``true``, the {+driver-short+} + still verifies any OCSP response stapled to a server's certificate. + +.. _php-crl: + +Certificate Revocation List +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instead of using OCSP, you can use the instruct the {+driver-short+} +to check the server's certificate +against a Certificate Revocation List (CRL) published by the CA. To do so, set the +``crl_file`` option to the file path of the CRL. Include this option in the +``driverOptions`` parameter of the ``MongoDB\Client`` constructor, as shown +in the following code example: + +.. literalinclude:: /includes/connect/crl-file.php + :language: php + :copyable: true + +.. tip:: + + You can specify a CRL file in either the ``.pem`` or ``.der`` format. + +.. _php-client-cert: + +Present a Client Certificate +---------------------------- + +Some MongoDB deployments require every connecting application to present a client certificate +that proves its identity. To specify the client certificate for the {+driver-short+} to +present, set the ``tleCertificateKeyFile`` option to the file path of the ``.pem`` file that +contains your certificate and private key. + +You can do this in two ways: by using the ``uriOptions`` parameter +of the ``MongoDB\Client`` constructor or through a parameter in your connection string. + +.. include:: /includes/connect/client-cert-tabs.rst + +.. important:: + + Your client certificate and private key must be in the same ``.pem`` file. If they + are stored in different files, you must concatenate them. The following example + shows how to concatenate a key file and a certificate file into a third file called + ``combined.pem`` on a Unix system: + + .. code-block:: sh + + $ cat key.pem cert.pem > combined.pem + +.. _php-key-file-password: + +Provide a Key Password +~~~~~~~~~~~~~~~~~~~~~~ + +If the private key in your certificate file is encrypted, you must use the +``tlsCertificateKeyFilePassword`` option to provide the password. +You can do this in two ways: by using the ``uriOptions`` parameter +of the ``MongoDB\Client`` constructor or through a parameter in your connection string. + +.. include:: /includes/connect/key-file-password.rst + +.. _php-insecure-tls: + +Allow Insecure TLS +------------------ + +When TLS is enabled, the {+driver-short+} automatically verifies the certificate that +the server presents. When testing your code, you can disable this verification. +This is known as *insecure TLS.* + +When insecure TLS is enabled, the driver requires only that the server present an +X.509 certificate. The driver accepts a certificate even if any of the following are +true: + +- The hostname of the server and the subject name (or subject alternative name) + on the certificate don't match. +- The certificate is expired or not yet valid. +- The certificate doesn't have a trusted root certificate in the chain. +- The certificate purpose isn't valid for server identification. + +.. note:: + + Even when insecure TLS is enabled, communication between the client and server + is encrypted with TLS. + +To enable insecure TLS, set the ``tlsInsecure`` connection +option to ``true``. You can do this in two ways: by passing an argument to the +``MongoDB\Client`` constructor or through a parameter in your connection string. + +.. include:: /includes/connect/insecure-tls-tabs.rst + +To disable only certificate validation, set the ``tlsAllowInvalidCertificates`` option to +``true``, and set the ``tlsInsecure`` option to ``false`` or omit it: + +.. include:: /includes/connect/disable-cert-validation-tabs.rst + +To disable only hostname verification, set the ``tlsAllowInvalidHostnames`` option to +``true``, and set the ``tlsInsecure`` option to ``false`` or omit it: + +.. include:: /includes/connect/disable-host-verification-tabs.rst + +.. warning:: Don't Use in Production + + Always set the ``tlsInsecure``, ``tlsAllowInvalidCertificates``, and + ``tlsAllowInvalidHostnames`` options to ``false`` in production. + + Setting any of these options to ``true`` in a production environment makes + your application insecure and potentially + vulnerable to expired certificates and to foreign processes posing + as valid client instances. + +API Documentation +----------------- + +To learn more about configuring TLS for the {+driver-short+}, +see the following API documentation: + +- :ref:`MongoDB\Client ` \ No newline at end of file diff --git a/source/includes/connect/ca-dir.php b/source/includes/connect/ca-dir.php new file mode 100644 index 00000000..3618529b --- /dev/null +++ b/source/includes/connect/ca-dir.php @@ -0,0 +1,11 @@ +$uri = "mongodb://:"; + +$uriOptions = [ + 'tls' => true, +]; + +$driverOptions = [ + 'ca_dir' => '/path/to/search/' +]; + +$client = new MongoDB\Client($uri, $uriOptions, $driverOptions); diff --git a/source/includes/connect/ca-file-tabs.rst b/source/includes/connect/ca-file-tabs.rst new file mode 100644 index 00000000..b0b85bc8 --- /dev/null +++ b/source/includes/connect/ca-file-tabs.rst @@ -0,0 +1,23 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true, + 'tlsCAFile' => '/path/to/ca.pem' + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true&tlsCAFile=/path/to/ca.pem"; + $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/client-cert-tabs.rst b/source/includes/connect/client-cert-tabs.rst new file mode 100644 index 00000000..961fc987 --- /dev/null +++ b/source/includes/connect/client-cert-tabs.rst @@ -0,0 +1,23 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true, + 'tlsCertificateKeyFile' => '/path/to/client.pem' + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/client.pem"; + $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/crl-file.php b/source/includes/connect/crl-file.php new file mode 100644 index 00000000..1a37b5e2 --- /dev/null +++ b/source/includes/connect/crl-file.php @@ -0,0 +1,11 @@ +$uri = "mongodb://:"; + +$uriOptions = [ + 'tls' => true, +]; + +$driverOptions = [ + 'crl_file' => '/path/to/file.pem' +]; + +$client = new MongoDB\Client($uri, $uriOptions, $driverOptions); diff --git a/source/includes/connect/crl-tabs.rst b/source/includes/connect/crl-tabs.rst new file mode 100644 index 00000000..f0a63f9d --- /dev/null +++ b/source/includes/connect/crl-tabs.rst @@ -0,0 +1,23 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true, + 'tlsCRLFile' => '/path/to/crl.pem' + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true&tlsCRLFile=/path/to/crl.pem"; + $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/disable-cert-validation-tabs.rst b/source/includes/connect/disable-cert-validation-tabs.rst new file mode 100644 index 00000000..bcdc0e76 --- /dev/null +++ b/source/includes/connect/disable-cert-validation-tabs.rst @@ -0,0 +1,23 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true, + 'tlsAllowInvalidCertificates' => true + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true&tlsAllowInvalidCertificates=true"; + $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/disable-host-verification-tabs.rst b/source/includes/connect/disable-host-verification-tabs.rst new file mode 100644 index 00000000..db4b8d1b --- /dev/null +++ b/source/includes/connect/disable-host-verification-tabs.rst @@ -0,0 +1,23 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true, + 'tlsAllowInvalidHostnames' => true + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true&tlsAllowInvalidHostnames=true"; + $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/insecure-tls-tabs.rst b/source/includes/connect/insecure-tls-tabs.rst new file mode 100644 index 00000000..97600fbf --- /dev/null +++ b/source/includes/connect/insecure-tls-tabs.rst @@ -0,0 +1,23 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true, + 'tlsInsecure' => true + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true&tlsInsecure=true"; + $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/key-file-password.rst b/source/includes/connect/key-file-password.rst new file mode 100644 index 00000000..2cb710c9 --- /dev/null +++ b/source/includes/connect/key-file-password.rst @@ -0,0 +1,24 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true, + 'tlsCertificateKeyFile' => '/path/to/client.pem', + 'tlsCertificateKeyFilePassword' => '' + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/client.pem&tlsCertificateKeyFilePassword="; + $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/ocsp-tabs.rst b/source/includes/connect/ocsp-tabs.rst new file mode 100644 index 00000000..1e393689 --- /dev/null +++ b/source/includes/connect/ocsp-tabs.rst @@ -0,0 +1,23 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true, + 'tlsDisableOCSPEndpointCheck' => true + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true&tlsDisableOCSPEndpointCheck=true"; + $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/tls-tabs.rst b/source/includes/connect/tls-tabs.rst new file mode 100644 index 00000000..1bb80731 --- /dev/null +++ b/source/includes/connect/tls-tabs.rst @@ -0,0 +1,22 @@ +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: mongoclient + + .. code-block:: php + + $uri = "mongodb://:"; + + $options = [ + 'tls' => true + ]; + + $client = new MongoDB\Client($uri, $options); + + .. tab:: Connection String + :tabid: connectionstring + + .. code-block:: php + + $uri = "mongodb://:/?tls=true"; + $client = MongoDB\Client($uri); \ No newline at end of file From 09c7be492999129e5d7ae767040f73ab35458982 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Thu, 29 Aug 2024 16:10:08 -0400 Subject: [PATCH 014/149] DOCSP-41978: Count documents (#108) * DOCSP-41978: Count documents * edits * code ex format * link * RR feedback --- source/includes/read/count.php | 44 ++++++ source/read.txt | 3 +- source/read/count.txt | 252 +++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 source/includes/read/count.php create mode 100644 source/read/count.txt diff --git a/source/includes/read/count.php b/source/includes/read/count.php new file mode 100644 index 00000000..3167cb90 --- /dev/null +++ b/source/includes/read/count.php @@ -0,0 +1,44 @@ +sample_training->companies; +// end-db-coll + +// Counts all documents in the collection +// start-count-all +$result = $collection->countDocuments([]); +echo "Number of documents: " . $result; +// end-count-all + +// Counts documents that have a "founded_year" value of 2010 +// start-count-accurate +$result = $collection->countDocuments(['founded_year' => 2010]); +echo "Number of companies founded in 2010: " . $result; +// end-count-accurate + +// Counts a maximum of 100 documents that have a "number_of_employees" value of 50 +// start-modify-accurate +$result = $collection->countDocuments( + ['number_of_employees' => 50], + ['limit' => 100] +); +echo "Number of companies with 50 employees: " . $result; +// end-modify-accurate + +// Estimates the number of documents in the collection +// start-count-estimate +$result = $collection->estimatedDocumentCount(); +echo "Estimated number of documents: " . $result; +// end-count-estimate + +// Estimates the number of documents in the collection and sets a time limit on the operation +// start-modify-estimate +$result = $collection->estimatedDocumentCount(['maxTimeMS' => 1000]); +echo "Estimated number of documents: " . $result; +// end-modify-estimate diff --git a/source/read.txt b/source/read.txt index a3f245ca..be850609 100644 --- a/source/read.txt +++ b/source/read.txt @@ -9,6 +9,7 @@ Read Data from MongoDB :maxdepth: 1 /read/retrieve + /read/project + /read/count /read/specify-documents-to-return /read/specify-a-query - /read/project \ No newline at end of file diff --git a/source/read/count.txt b/source/read/count.txt new file mode 100644 index 00000000..5b825a78 --- /dev/null +++ b/source/read/count.txt @@ -0,0 +1,252 @@ +.. _php-count: + +=============== +Count Documents +=============== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: number, amount, estimation, code example + +Overview +--------- + +In this guide, you can learn how to use the {+php-library+} to retrieve an accurate +and estimated count of the number of documents in a collection. The following methods +count documents in a collection: + +- ``MongoDB\Collection::countDocuments()``: Returns the exact number of documents that + match a query filter or that exist in a collection + +- ``MongoDB\Collection::estimatedDocumentCount()``: Returns the estimated number of documents + in a collection + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``companies`` collection in the ``sample_training`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``collection`` variable: + +.. literalinclude:: /includes/read/count.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +.. _php-accurate-count: + +Retrieve an Accurate Count +-------------------------- + +Use the ``MongoDB\Collection::countDocuments()`` method to count the number of documents +in a collection. To count the number of documents that match specific search criteria, +pass a query filter to the ``countDocuments()`` method. + +To learn more about specifying a query, see the :ref:`php-specify-query` guide. + +Count All Documents +~~~~~~~~~~~~~~~~~~~ + +To return a count of all documents in the collection, pass an empty query filter array to +the ``countDocuments()`` method, as shown in the following example: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/count.php + :start-after: start-count-all + :end-before: end-count-all + :language: php + :dedent: + + .. output:: + :visible: false + + Number of documents: 9500 + +Count Specific Documents +~~~~~~~~~~~~~~~~~~~~~~~~ + +To return a count of documents that match specific search criteria, pass a query +filter to the ``countDocuments()`` method. + +The following example counts the number of documents in which the value of the +``founded_year`` field is ``2010``: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/count.php + :start-after: start-count-accurate + :end-before: end-count-accurate + :language: php + :dedent: + + .. output:: + :visible: false + + Number of companies founded in 2010: 33 + +Customize Count Behavior +~~~~~~~~~~~~~~~~~~~~~~~~ + +You can modify the behavior of the ``countDocuments()`` method by +passing an array that specifies option values. The following table +describes some options you can set to customize the count operation: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``collation`` + - | The collation to use for the operation. + | **Type**: ``array|object`` + + * - ``hint`` + - | The index to use for the operation. + | **Type**: ``string|array|object`` + + * - ``comment`` + - | The comment to attach to the operation. + | **Type**: any valid BSON type + + * - ``limit`` + - | The maximum number of documents to count. This value must be a positive integer. + | **Type**: ``integer`` + + * - ``maxTimeMS`` + - | The maximum amount of time in milliseconds that the operation can run. + | **Type**: ``integer`` + + * - ``skip`` + - | The number of documents to skip before counting documents. + | **Type**: ``integer`` + + * - ``readPreference`` + - | The read preference to use for the operation. To learn more, see + :manual:`Read Preference ` in the Server manual. + | **Type**: ``MongoDB\Driver\ReadPreference`` + +The following example uses the ``countDocuments()`` method to count the number of +documents in which the ``number_of_employees`` field has the value ``50`` and instructs the +operation to count a maximum of ``100`` results: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/count.php + :start-after: start-modify-accurate + :end-before: end-modify-accurate + :language: php + :dedent: + + .. output:: + :visible: false + + Number of companies with 50 employees: 100 + +.. _php-estimated-count: + +Retrieve an Estimated Count +--------------------------- + +You can retrieve an estimate of the number of documents in a collection by calling +the ``MongoDB\Collection::estimatedDocumentCount()`` method. The method estimates +the amount of documents based on collection metadata, which might be faster than +performing an accurate count. + +The following example estimates the number of documents in a collection: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/count.php + :start-after: start-count-estimate + :end-before: end-count-estimate + :language: php + :dedent: + + .. output:: + :visible: false + + Estimated number of documents: 9500 + +Customize Estimated Count Behavior +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can modify the behavior of the ``estimatedDocumentCount()`` method +by passing an array that specifies option values as a parameter. The +following table describes the options you can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``comment`` + - | The comment to attach to the operation. + | **Type**: any valid BSON type + + * - ``maxTimeMS`` + - | The maximum amount of time in milliseconds that the operation can run. + | **Type**: ``integer`` + + * - ``readConcern`` + - | The read concern to use for the operation. To learn more, see + :manual:`Read Concern ` in the Server manual. + | **Type**: ``MongoDB\Driver\ReadConcern`` + + * - ``readPreference`` + - | The read preference to use for the operation. To learn more, see + :manual:`Read Preference ` in the Server manual. + | **Type**: ``MongoDB\Driver\ReadPreference`` + + * - ``session`` + - | The client session to associate with the operation. + | **Type**: ``MongoDB\Driver\Session`` + +The following example uses the ``estimatedDocumentCount()`` method to return an +estimate of the number of documents in the collection and sets a timeout of +``1000`` milliseconds on the operation: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/count.php + :start-after: start-modify-estimate + :end-before: end-modify-estimate + :language: php + :dedent: + + .. output:: + :visible: false + + Estimated number of documents: 9500 + +API Documentation +----------------- + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::countDocuments() <{+api+}/method/MongoDBCollection-countDocuments/>`__ +- `MongoDB\\Collection::estimatedDocumentCount() <{+api+}/method/MongoDBCollection-estimatedDocumentCount/>`__ \ No newline at end of file From 7e0f9be21a61520f658a4324fdaa3dd3177d0e14 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Tue, 3 Sep 2024 13:31:12 -0400 Subject: [PATCH 015/149] DOCSP-41979: Distinct values (#109) Adds a Distinct Values guide. --- snooty.toml | 1 - source/includes/read/distinct.php | 40 +++++++ source/read.txt | 3 +- source/read/distinct.txt | 171 ++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 source/includes/read/distinct.php create mode 100644 source/read/distinct.txt diff --git a/snooty.toml b/snooty.toml index e30bbbc3..a77d00d6 100644 --- a/snooty.toml +++ b/snooty.toml @@ -28,5 +28,4 @@ php-library = "MongoDB PHP Library" php-library = "MongoDB PHP Library" driver-short = "PHP library" mdb-server = "MongoDB Server" -driver-short = "PHP library" api = "https://www.mongodb.com/docs/php-library/current/reference" diff --git a/source/includes/read/distinct.php b/source/includes/read/distinct.php new file mode 100644 index 00000000..5ac02f97 --- /dev/null +++ b/source/includes/read/distinct.php @@ -0,0 +1,40 @@ +sample_restaurants->restaurants; +// end-db-coll + +// Retrieves distinct values of the "borough" field +// start-distinct +$results = $collection->distinct('borough', []); +foreach ($results as $value) { + echo json_encode($value) . PHP_EOL; +} +// end-distinct + +// Retrieves distinct "borough" field values for documents with a "cuisine" value of "Italian" +// start-distinct-with-query +$results = $collection->distinct('borough', ['cuisine' => 'Italian']); +foreach ($results as $value) { + echo json_encode($value) . PHP_EOL; +} +// end-distinct-with-query + +// Retrieves distinct "name" field values for documents matching the "borough" and "cuisine" fields query +// and attaches a comment to the operation +// start-distinct-with-comment +$query = ['borough' => 'Bronx', 'cuisine' => 'Pizza']; +$options = ['comment' => 'Bronx pizza restaurants']; +$results = $collection->distinct('name', $query, $options); + +foreach ($results as $value) { + echo json_encode($value) . PHP_EOL; +} +// end-distinct-with-comment + diff --git a/source/read.txt b/source/read.txt index be850609..d0299830 100644 --- a/source/read.txt +++ b/source/read.txt @@ -7,9 +7,10 @@ Read Data from MongoDB .. toctree:: :titlesonly: :maxdepth: 1 - + /read/retrieve /read/project /read/count /read/specify-documents-to-return /read/specify-a-query + /read/distinct diff --git a/source/read/distinct.txt b/source/read/distinct.txt new file mode 100644 index 00000000..18b9de2f --- /dev/null +++ b/source/read/distinct.txt @@ -0,0 +1,171 @@ +.. _php-distinct: + +============================== +Retrieve Distinct Field Values +============================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: read, unique, code example + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to retrieve the +distinct values of a specified field across a collection. + +Within a collection, different documents might contain different values for a +single field. For example, one document in a ``restaurants`` collection has a +``borough`` value of ``'Manhattan'``, and another has a ``borough`` value of +``'Queens'``. By using the {+php-library+}, you can retrieve all the unique values +that a field contains across multiple documents in a collection. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``collection`` variable: + +.. literalinclude:: /includes/read/distinct.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +``MongoDB\Collection::distinct()`` Method +----------------------------------------- + +To retrieve the distinct values for a specified field, call the ``MongoDB\Collection::distinct()`` +method and pass in the name of the field you want to find distinct values for. + +Retrieve Distinct Values Across a Collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example retrieves the distinct values of the ``borough`` field in +the ``restaurants`` collection: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/distinct.php + :start-after: start-distinct + :end-before: end-distinct + :language: php + :dedent: + + .. output:: + + "Bronx" + "Manhattan" + "Missing" + "Queens" + "Staten Island" + +The operation returns an array that stores each distinct ``borough`` field value. Although +several documents have the same value in the ``borough`` field, each value appears in the +results only once. + +Retrieve Distinct Values Across Specified Documents +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can provide a **query filter** to the ``distinct()`` method to find the distinct +field values across a subset of documents in a collection. A query filter is an expression +that specifies search criteria used to match documents in an operation. For more information +about creating a query filter, see the :ref:`php-specify-query` guide. + +The following example retrieves the distinct values of the ``borough`` field for +all documents that have a ``cuisine`` field value of ``'Italian'``: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/distinct.php + :start-after: start-distinct-with-query + :end-before: end-distinct-with-query + :language: php + :dedent: + + .. output:: + :visible: false + + "Bronx" + "Manhattan" + "Queens" + "Staten Island" + +Modify Distinct Behavior +~~~~~~~~~~~~~~~~~~~~~~~~ + +You can modify the behavior of the ``distinct()`` method by passing an +array that specifies option values. The following table describes some +options you can set to customize the operation: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``collation`` + - | The collation to use for the operation. + | **Type**: ``array|object`` + + * - ``maxTimeMS`` + - | The maximum amount of time in milliseconds that the operation can run. + | **Type**: ``integer`` + + * - ``comment`` + - | The comment to attach to the operation. + | **Type**: any valid BSON type + + * - ``readPreference`` + - | The read preference to use for the operation. To learn more, see + :manual:`Read Preference ` in the Server manual. + | **Type**: ``MongoDB\Driver\ReadPreference`` + +The following example retrieves the distinct values of the ``name`` field for +all documents that have a ``borough`` field value of ``'Bronx'`` and a +``cuisine`` field value of ``'Pizza'``. It also specifies the ``comment`` field +in an options array to add a comment to the operation: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/distinct.php + :start-after: start-distinct-with-comment + :end-before: end-distinct-with-comment + :language: php + :dedent: + + .. output:: + :visible: false + + "$1.25 Pizza" + "18 East Gunhill Pizza" + "2 Bros" + "Aenos Pizza" + "Alitalia Pizza Restaurant" + "Amici Pizza And Pasta" + "Angie'S Cafe Pizza" + ... + +API Documentation +----------------- + +To learn more about the ``MongoDB\Collection::distinct()`` method, see the +`distinct() API documentation <{+api+}/method/MongoDBCollection-distinct/>`__. \ No newline at end of file From cd4c81f5e01814ccc5c727f969d321e5d6c63863 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Thu, 5 Sep 2024 13:33:51 -0400 Subject: [PATCH 016/149] DOCSP-41981: Change streams (#113) Adds a Change Streams guide. --- source/includes/read/change-streams.php | 78 +++++++ source/read.txt | 1 + source/read/change-streams.txt | 268 ++++++++++++++++++++++++ 3 files changed, 347 insertions(+) create mode 100644 source/includes/read/change-streams.php create mode 100644 source/read/change-streams.txt diff --git a/source/includes/read/change-streams.php b/source/includes/read/change-streams.php new file mode 100644 index 00000000..5b51d1a6 --- /dev/null +++ b/source/includes/read/change-streams.php @@ -0,0 +1,78 @@ +toRelaxedExtendedJSON(); +} +// end-to-json + +$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your Atlas URI that connects to the sample dataset'); +$client = new MongoDB\Client($uri); + +// start-db-coll +$collection = $client->sample_restaurants->restaurants; +// end-db-coll + +// Monitors and prints changes to the "restaurants" collection +// start-open-change-stream +$changeStream = $collection->watch(); + +for ($changeStream->rewind(); true; $changeStream->next()) { + if ( ! $changeStream->valid()) { + continue; + } + $event = $changeStream->current(); + echo toJSON($event) . PHP_EOL; + + if ($event['operationType'] === 'invalidate') { + break; + } +} +// end-open-change-stream + +// Updates a document that has a "name" value of "Blarney Castle" +// start-update-for-change-stream +$result = $collection->updateOne( + ['name' => 'Blarney Castle'], + ['$set' => ['cuisine' => 'Irish']] +); +// end-update-for-change-stream + +// Passes a pipeline argument to watch() to monitor only update operations +// start-change-stream-pipeline +$pipeline = [['$match' => ['operationType' => 'update']]]; +$changeStream = $collection->watch($pipeline); + +for ($changeStream->rewind(); true; $changeStream->next()) { + if ( ! $changeStream->valid()) { + continue; + } + $event = $changeStream->current(); + echo toJSON($event) . PHP_EOL; + + if ($event['operationType'] === 'invalidate') { + break; + } +} +// end-change-stream-pipeline + +// Passes an options argument to watch() to include the post-image of updated documents +// start-change-stream-post-image +$options = ['fullDocument' => MongoDB\Operation\Watch::FULL_DOCUMENT_UPDATE_LOOKUP]; +$changeStream = $collection->watch([], $options); + +for ($changeStream->rewind(); true; $changeStream->next()) { + if ( ! $changeStream->valid()) { + continue; + } + $event = $changeStream->current(); + echo toJSON($event) . PHP_EOL; + + if ($event['operationType'] === 'invalidate') { + break; + } +} +// end-change-stream-post-image + diff --git a/source/read.txt b/source/read.txt index d0299830..a45c2a82 100644 --- a/source/read.txt +++ b/source/read.txt @@ -14,3 +14,4 @@ Read Data from MongoDB /read/specify-documents-to-return /read/specify-a-query /read/distinct + /read/change-streams diff --git a/source/read/change-streams.txt b/source/read/change-streams.txt new file mode 100644 index 00000000..757c1e7b --- /dev/null +++ b/source/read/change-streams.txt @@ -0,0 +1,268 @@ +.. _php-change-streams: + +==================== +Monitor Data Changes +==================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: watch, code example + +Overview +-------- + +In this guide, you can learn how to use a **change stream** to monitor real-time +changes to your data. A change stream is a {+mdb-server+} feature that +allows your application to subscribe to data changes on a collection, database, +or deployment. + +When using the {+php-library+}, you can call the ``watch()`` method to return an +instance of ``MongoDB\ChangeStream``. Then, you can iterate through the +``MongoDB\ChangeStream`` instance to monitor data changes, such as updates, +insertions, and deletions. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``$collection`` variable: + +.. literalinclude:: /includes/read/change-streams.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +.. tip:: + + To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the + :atlas:`Get Started with Atlas ` guide. + +Some examples use the ``toJSON()`` function to represent change events, which are BSON +documents, as Extended JSON. To use this function, paste the following code into your +application file: + +.. literalinclude:: /includes/read/change-streams.php + :language: php + :dedent: + :start-after: start-to-json + :end-before: end-to-json + +Open a Change Stream +-------------------- + +To open a change stream, call the ``watch()`` method. The instance on which you +call the ``watch()`` method determines the scope of events that the change +stream monitors. You can call the ``watch()`` method on instances of the following +classes: + +- ``MongoDB\Client``: Monitor all changes in the MongoDB deployment +- ``MongoDB\Database``: Monitor changes in all collections in the database +- ``MongoDB\Collection``: Monitor changes in the collection + +The following example opens a change stream on the ``restaurants`` collection +and outputs changes as they occur: + +.. literalinclude:: /includes/read/change-streams.php + :start-after: start-open-change-stream + :end-before: end-open-change-stream + :language: php + :dedent: + +To begin watching for changes, run the preceding code. Then, in a separate +shell, modify the ``restaurants`` collection. The following example updates +a document that has a ``name`` field value of ``'Blarney Castle'``: + +.. _php-change-stream-update: + +.. literalinclude:: /includes/read/change-streams.php + :start-after: start-update-for-change-stream + :end-before: end-update-for-change-stream + :language: php + :dedent: + +When you update the collection, the change stream application prints the change +as it occurs. The printed change event resembles the following output: + +.. code-block:: none + :copyable: false + + { "_id" : { "_data" : "..." }, "operationType" : "update", "clusterTime" : + { "$timestamp" : { ... } }, "wallTime" : { "$date" : "..." }, "ns" : { "db" : + "sample_restaurants", "coll" : "restaurants" }, "documentKey" : { "_id" : + { "$oid" : "..." } }, "updateDescription" : { "updatedFields" : { "cuisine" : "Irish" }, + "removedFields" : [ ], "truncatedArrays" : [ ] } } + +Modify the Change Stream Output +------------------------------- + +To modify the change stream output, you can pass pipeline stages in an array as a +parameter to the ``watch()`` method. You can include the following stages in the +array: + +- ``$addFields`` or ``$set``: Adds new fields to documents +- ``$match``: Filters the documents +- ``$project``: Projects a subset of the document fields +- ``$replaceWith`` or ``$replaceRoot``: Replaces the input document with the + specified document +- ``$redact``: Restricts the contents of the documents +- ``$unset``: Removes fields from documents + +The following example passes a pipeline that includes the ``$match`` stage to the +``watch()`` method. This instructs the ``watch()`` method to output events only +when update operations occur: + +.. literalinclude:: /includes/read/change-streams.php + :start-after: start-change-stream-pipeline + :end-before: end-change-stream-pipeline + :language: php + :dedent: + +Modify ``watch()`` Behavior +--------------------------- + +To modify the behavior of the ``watch()`` method, you can pass an options array +as a parameter to ``watch()``. The following table describes useful options you +can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``fullDocument`` + - | Specifies whether to show the full document after the change, rather + than showing only the changes made to the document. To learn more about + this option, see the :ref:`php-change-stream-pre-post-image` section of this + guide. + + * - ``fullDocumentBeforeChange`` + - | Specifies whether to show the full document as it was before the change, rather + than showing only the changes made to the document. To learn more about + this option, see :ref:`php-change-stream-pre-post-image`. + + * - ``startAfter`` + - | Instructs ``watch()`` to start a new change stream after the + operation specified in the resume token. This field allows notifications to + resume after an invalidate event. + | Each change stream event document includes a resume token as the ``_id`` + field. Pass the entire ``_id`` field of the change event document that + represents the operation you want to resume after. + | This option is mutually exclusive with ``resumeAfter`` and ``startAtOperationTime``. + + * - ``startAtOperationTime`` + - | Instructs the change stream to only provide changes that occurred at or after + the specified timestamp. + | This option is mutually exclusive with ``startAfter`` and ``resumeAfter``. + + * - ``collation`` + - | Sets the collation to use for the change stream cursor. + +For a full list of ``watch()`` options, see `MongoDB\\Collection::watch() +<{+api+}/method/MongoDBCollection-watch/>`__ in the API +documentation. + +.. _php-change-stream-pre-post-image: + +Include Pre-Images and Post-Images +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. important:: + + You can enable pre-images and post-images on collections only if your + deployment uses MongoDB v6.0 or later. + +By default, when you perform an operation on a collection, the +corresponding change event includes only the delta of the fields +modified by that operation. To see the full document before or after a +change, specify the ``fullDocumentBeforeChange`` or the ``fullDocument`` +options in an array parameter to ``watch()``. + +The **pre-image** is the full version of a document *before* a change. To include the +pre-image in the change stream event, set the ``fullDocumentBeforeChange`` option +to one of the following values: + +- ``MongoDB\Operation\Watch::FULL_DOCUMENT_BEFORE_CHANGE_WHEN_AVAILABLE``: The change event includes + a pre-image of the modified document for change events. If the pre-image is not available, this + change event field has a ``null`` value. +- ``MongoDB\Operation\Watch::FULL_DOCUMENT_BEFORE_CHANGE_REQUIRED``: The change event includes a pre-image + of the modified document for change events. If the pre-image is not available, the + server raises an error. + +The **post-image** is the full version of a document *after* a change. To include the +post-image in the change stream event, set the ``fullDocument`` option to +one of the following values: + +- ``MongoDB\Operation\Watch::FULL_DOCUMENT_UPDATE_LOOKUP``: The change event includes a + copy of the entire changed document from some time after the change. +- ``MongoDB\Operation\Watch::FULL_DOCUMENT_WHEN_AVAILABLE``: The change event includes + a post-image of the modified document for change events. If the post-image is not + available, this change event field has a ``null`` value. +- ``MongoDB\Operation\Watch::FULL_DOCUMENT_REQUIRED``: The change event includes a post-image + of the modified document for change events. If the post-image is not available, the + server raises an error. + +The following example calls the ``watch()`` method on a collection and includes the post-image +of updated documents by setting the ``fullDocument`` option: + +.. literalinclude:: /includes/read/change-streams.php + :start-after: start-change-stream-post-image + :end-before: end-change-stream-post-image + :language: php + :dedent: + +With the change stream application running in a separate shell, updating a +document in the ``restaurants`` collection by using the :ref:`preceding update +example ` prints a change event resembling the following +output: + +.. code-block:: none + :copyable: false + :emphasize-lines: 3-6 + + { "_id" : { "_data" : "..." }, "operationType" : "update", "clusterTime" : + { "$timestamp" : { ... } }, "wallTime" : { "$date" : "..." }, + "fullDocument" : { "_id" : { "$oid" : "..." }, "address" : { "building" : + "202-24", "coord" : [ -73.925044200000002093, 40.559546199999999772 ], "street" + : "Rockaway Point Boulevard", "zipcode" : "11697" }, "borough" : "Queens", + "cuisine" : "Irish", "grades" : [ ...], "name" : "Blarney Castle", "restaurant_id" : + "40366356" }, "ns" : { "db" : "sample_restaurants", "coll" : "restaurants" }, + "documentKey" : { "_id" : { "$oid" : "..." } }, "updateDescription" : + { "updatedFields" : { "cuisine" : "Irish" }, "removedFields" : [ ], + "truncatedArrays" : [ ] } } + +.. tip:: + + To learn more about pre-images and post-images, see + :manual:`Change Streams with Document Pre- and Post-Images ` + in the {+mdb-server+} manual. + +Additional Information +---------------------- + +To learn more about change streams, see :manual:`Change Streams +` in the {+mdb-server+} manual. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Client::watch() <{+api+}/method/MongoDBClient-watch/>`__ +- `MongoDB\\Database::watch() <{+api+}/method/MongoDBDatabase-watch/>`__ +- `MongoDB\\Collection::watch() <{+api+}/method/MongoDBCollection-watch/>`__ +- `MongoDB\\Collection::updateOne() <{+api+}/method/MongoDBCollection-updateOne/>`__ \ No newline at end of file From 169702e780079b03486a46f23a541f7e3efc2179 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 14:59:02 -0400 Subject: [PATCH 017/149] DOCSP-41993 Compatibility Table --- source/compatibility.txt | 44 +++ .../mongodb-compatibility-table-php.rst | 280 ++++++++++++++++++ .../read/language-compatibility-table-php.rst | 212 +++++++++++++ 3 files changed, 536 insertions(+) create mode 100644 source/compatibility.txt create mode 100644 source/includes/mongodb-compatibility-table-php.rst create mode 100644 source/includes/read/language-compatibility-table-php.rst diff --git a/source/compatibility.txt b/source/compatibility.txt new file mode 100644 index 00000000..5df5720c --- /dev/null +++ b/source/compatibility.txt @@ -0,0 +1,44 @@ +.. _php-compatibility: + +============= +Compatibility +============= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: backwards compatibility, versions, upgrade + +MongoDB Compatibility +~~~~~~~~~~~~~~~~~~~~~ + +The following compatibility table specifies the recommended version or versions +of the PHP driver for use with a specific version of MongoDB. + +The first column lists the driver version. + +.. sharedinclude:: dbx/lifecycle-schedule-callout.rst + +.. include:: /includes/mongodb-compatibility-table-php.rst + +Language Compatibility +~~~~~~~~~~~~~~~~~~~~~~ + +The following compatibility table specifies the recommended version or versions +of the PHP driver for use with a specific version of PHP. + +The first column lists the driver versions. + +.. include:: /includes/language-compatibility-table-php.rst + +.. sharedinclude:: dbx/about-driver-compatibility.rst + +.. sharedinclude:: dbx/help-links-php.rst diff --git a/source/includes/mongodb-compatibility-table-php.rst b/source/includes/mongodb-compatibility-table-php.rst new file mode 100644 index 00000000..710b506e --- /dev/null +++ b/source/includes/mongodb-compatibility-table-php.rst @@ -0,0 +1,280 @@ +.. sharedinclude:: dbx/compatibility-table-legend.rst + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + :class: compatibility-large + + * - PHP Driver Versions + - MongoDB 8.0 + - MongoDB 7.0 + - MongoDB 6.0 + - MongoDB 5.0 + - MongoDB 4.4 + - MongoDB 4.2 + - MongoDB 4.0 + - MongoDB 3.6 + - MongoDB 3.4 + - MongoDB 3.2 + - MongoDB 3.0 + - MongoDB 2.6 + + * - ext + lib 1.20 + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + - + + * - ext + lib 1.16 to 1.19 + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext + lib 1.15 [#PHP1.15-version-parity]_ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext 1.14 + lib 1.13 + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext 1.13 + lib 1.12 + - ⊛ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext 1.12 + lib 1.11 + - ⊛ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.11 + lib 1.10 + - ⊛ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.10 + lib 1.9 + - ⊛ + - ⊛ + - ⊛ + - ✓ [#PHPC1.10-PHPLIB1.9-driver-support]_ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.9 + lib 1.8 + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.8 + lib 1.7 + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.7 + lib 1.6 + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.6 + lib 1.5 + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.5 + lib 1.4 + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ⊛ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.4 + lib 1.3 + - + - + - + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + + * - ext 1.3 + lib 1.2 + - + - + - + - + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + + * - ext 1.2 + lib 1.1 + - + - + - + - + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + + * - ext 1.1 + lib 1.0 + - + - + - + - + - + - + - + - + - + - ✓ + - ✓ + - ✓ + + * - ext 1.0 + - + - + - + - + - + - + - + - + - + - + - ✓ + - ✓ + +.. [#PHP1.15-version-parity] Version 1.14 of the MongoDB PHP library has been + skipped to restore version parity between the library and extension. + +.. [#PHPC1.10-PHPLIB1.9-driver-support] The extension 1.10 + library 1.9 + driver does not support snapshot reads on secondaries. For more + information, see the + `MongoDB Server version 5.0 release notes `__. \ No newline at end of file diff --git a/source/includes/read/language-compatibility-table-php.rst b/source/includes/read/language-compatibility-table-php.rst new file mode 100644 index 00000000..ef4cea14 --- /dev/null +++ b/source/includes/read/language-compatibility-table-php.rst @@ -0,0 +1,212 @@ +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + :class: compatibility-large + + * - PHP Driver Versions + - PHP 8.3 + - PHP 8.2 + - PHP 8.1 + - PHP 8.0 + - PHP 7.4 + - PHP 7.3 + - PHP 7.2 + - PHP 7.1 + - PHP 7.0 + - PHP 5.6 + - PHP 5.5 + + * - ext + lib 1.17 to 1.19 + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + - + - + + * - ext + lib 1.16 + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext + lib 1.15 [#PHP1.15-version-parity]_ + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext 1.14 + lib 1.13 + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext 1.13 + lib 1.12 + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext 1.12 + lib 1.11 + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + - + + * - ext 1.11 + lib 1.10 + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + + * - ext 1.10 + lib 1.9 + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + - + + * - ext 1.9 + lib 1.8 + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + + * - ext 1.8 + lib 1.7 + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + - + + * - ext 1.7 + lib 1.6 + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.6 + lib 1.5 + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - + + * - ext 1.5 + lib 1.4 + - + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + + * - ext 1.4 + lib 1.3 + - + - + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ + + * - ext 1.3 + lib 1.2 + - + - + - + - + - + - + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ \ No newline at end of file From c956ae9292dd1ab0feade72545b2e9eb10c02f68 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 15:11:49 -0400 Subject: [PATCH 018/149] test webhook --- source/compatibility.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/source/compatibility.txt b/source/compatibility.txt index 5df5720c..5d1eed6d 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -42,3 +42,4 @@ The first column lists the driver versions. .. sharedinclude:: dbx/about-driver-compatibility.rst .. sharedinclude:: dbx/help-links-php.rst + From c20a191d0aec1f63e3b3aa06bceccfa7dca888dd Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 15:42:15 -0400 Subject: [PATCH 019/149] toc and sharedincludes --- snooty.toml | 2 ++ source/index.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/snooty.toml b/snooty.toml index a77d00d6..948c81e2 100644 --- a/snooty.toml +++ b/snooty.toml @@ -23,6 +23,8 @@ toc_landing_pages = [ [substitutions] php-library = "MongoDB PHP Library" +sharedinclude_root = "https://raw.githubusercontent.com/10gen/docs-shared/main/" + [constants] php-library = "MongoDB PHP Library" diff --git a/source/index.txt b/source/index.txt index 38ff991f..ad34abc6 100644 --- a/source/index.txt +++ b/source/index.txt @@ -16,6 +16,7 @@ MongoDB PHP Library /upgrade /reference FAQ + /compatibility /whats-new The |php-library| provides a high-level abstraction around the lower-level From ea7b0e035521d52a9b4a72f196ea29d0ba4b6fe8 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 15:44:23 -0400 Subject: [PATCH 020/149] lang table --- source/includes/{read => }/language-compatibility-table-php.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename source/includes/{read => }/language-compatibility-table-php.rst (100%) diff --git a/source/includes/read/language-compatibility-table-php.rst b/source/includes/language-compatibility-table-php.rst similarity index 100% rename from source/includes/read/language-compatibility-table-php.rst rename to source/includes/language-compatibility-table-php.rst From 9dd5843d10c3b167112853a28afdc57f95ba15fc Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 15:53:02 -0400 Subject: [PATCH 021/149] edits --- source/compatibility.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source/compatibility.txt b/source/compatibility.txt index 5d1eed6d..970ab370 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -29,6 +29,9 @@ The first column lists the driver version. .. include:: /includes/mongodb-compatibility-table-php.rst +For more information on how to read the compatibility tables, see our guide on +`MongoDB Compatibility Tables. `__. + Language Compatibility ~~~~~~~~~~~~~~~~~~~~~~ @@ -43,3 +46,14 @@ The first column lists the driver versions. .. sharedinclude:: dbx/help-links-php.rst +For more information on how to read the compatibility tables, see our guide on +`MongoDB Compatibility Tables. `__. + +How to Get Help +--------------- + +If you have questions about compatibility, visit the following resources for further guidance: + +- Ask questions on our :community-forum:`MongoDB Community Forums <>`. +- Visit our :technical-support:`Support Channels `. +- See `Issues & Help `__. \ No newline at end of file From f59251d1ab378768a5980dcf72ae713fd6bd94e9 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 15:54:52 -0400 Subject: [PATCH 022/149] headings --- source/compatibility.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/compatibility.txt b/source/compatibility.txt index 970ab370..a14ecd6d 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -18,7 +18,7 @@ Compatibility :keywords: backwards compatibility, versions, upgrade MongoDB Compatibility -~~~~~~~~~~~~~~~~~~~~~ +--------------------- The following compatibility table specifies the recommended version or versions of the PHP driver for use with a specific version of MongoDB. @@ -33,7 +33,7 @@ For more information on how to read the compatibility tables, see our guide on `MongoDB Compatibility Tables. `__. Language Compatibility -~~~~~~~~~~~~~~~~~~~~~~ +---------------------- The following compatibility table specifies the recommended version or versions of the PHP driver for use with a specific version of PHP. From 3b0efec08eafb7ac7d17cec633fbea7d1c5dbd14 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 16:06:20 -0400 Subject: [PATCH 023/149] retry on shared include --- snooty.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snooty.toml b/snooty.toml index 948c81e2..78d56bb6 100644 --- a/snooty.toml +++ b/snooty.toml @@ -23,7 +23,7 @@ toc_landing_pages = [ [substitutions] php-library = "MongoDB PHP Library" -sharedinclude_root = "https://raw.githubusercontent.com/10gen/docs-shared/main/" +sharedinclude_root = "https://github.com/10gen/docs-shared/tree/main" [constants] From 4253547ea0dd386563bf1783ac33bbf71491d263 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 16:10:20 -0400 Subject: [PATCH 024/149] shared includes --- snooty.toml | 4 ++-- source/compatibility.txt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/snooty.toml b/snooty.toml index 78d56bb6..a074aa74 100644 --- a/snooty.toml +++ b/snooty.toml @@ -20,11 +20,11 @@ toc_landing_pages = [ "/get-started", ] +sharedinclude_root = "https://raw.githubusercontent.com/10gen/docs-shared/main/" + [substitutions] php-library = "MongoDB PHP Library" -sharedinclude_root = "https://github.com/10gen/docs-shared/tree/main" - [constants] php-library = "MongoDB PHP Library" diff --git a/source/compatibility.txt b/source/compatibility.txt index a14ecd6d..07e827fd 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -30,7 +30,7 @@ The first column lists the driver version. .. include:: /includes/mongodb-compatibility-table-php.rst For more information on how to read the compatibility tables, see our guide on -`MongoDB Compatibility Tables. `__. +`MongoDB Compatibility Tables `__. Language Compatibility ---------------------- @@ -47,7 +47,7 @@ The first column lists the driver versions. .. sharedinclude:: dbx/help-links-php.rst For more information on how to read the compatibility tables, see our guide on -`MongoDB Compatibility Tables. `__. +`MongoDB Compatibility Tables `__. How to Get Help --------------- @@ -56,4 +56,4 @@ If you have questions about compatibility, visit the following resources for fur - Ask questions on our :community-forum:`MongoDB Community Forums <>`. - Visit our :technical-support:`Support Channels `. -- See `Issues & Help `__. \ No newline at end of file +- See `Issues & Help `__. From 7a3b381d74187601b7fcd2cb2ff2385a2793bd0b Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 16:13:24 -0400 Subject: [PATCH 025/149] callout --- source/compatibility.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/compatibility.txt b/source/compatibility.txt index 07e827fd..9887ec8c 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -40,6 +40,8 @@ of the PHP driver for use with a specific version of PHP. The first column lists the driver versions. +.. sharedinclude:: dbx/lifecycle-schedule-callout.rst + .. include:: /includes/language-compatibility-table-php.rst .. sharedinclude:: dbx/about-driver-compatibility.rst From c82667068d6aa95f3084632251bb7e49d962a3b6 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 5 Sep 2024 16:18:49 -0400 Subject: [PATCH 026/149] help links --- source/compatibility.txt | 10 +++++----- source/includes/language-compatibility-table-php.rst | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/source/compatibility.txt b/source/compatibility.txt index 9887ec8c..79d11bb4 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -40,14 +40,10 @@ of the PHP driver for use with a specific version of PHP. The first column lists the driver versions. -.. sharedinclude:: dbx/lifecycle-schedule-callout.rst - .. include:: /includes/language-compatibility-table-php.rst .. sharedinclude:: dbx/about-driver-compatibility.rst -.. sharedinclude:: dbx/help-links-php.rst - For more information on how to read the compatibility tables, see our guide on `MongoDB Compatibility Tables `__. @@ -58,4 +54,8 @@ If you have questions about compatibility, visit the following resources for fur - Ask questions on our :community-forum:`MongoDB Community Forums <>`. - Visit our :technical-support:`Support Channels `. -- See `Issues & Help `__. +- File an issue or feature request in JIRA under one of the following: + + - `Extension `_ + + - `Library `_ \ No newline at end of file diff --git a/source/includes/language-compatibility-table-php.rst b/source/includes/language-compatibility-table-php.rst index ef4cea14..84e6a24e 100644 --- a/source/includes/language-compatibility-table-php.rst +++ b/source/includes/language-compatibility-table-php.rst @@ -1,3 +1,5 @@ +.. sharedinclude:: dbx/compatibility-table-legend.rst + .. list-table:: :header-rows: 1 :stub-columns: 1 From 429ea3bb878dfe0831a00e9d382c47a76dc83185 Mon Sep 17 00:00:00 2001 From: Mike Woofter <108414937+mongoKart@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:19:29 -0500 Subject: [PATCH 027/149] DOCSP-41958 - Connection Targets (#107) Co-authored-by: Nora Reidy Co-authored-by: Andreas Braun --- snooty.toml | 1 + source/connect/connection-targets.txt | 116 ++++++++++++++++++ source/includes/connect/atlas.php | 19 +++ source/includes/connect/direct-connection.php | 7 ++ source/includes/connect/replica-set.php | 6 + 5 files changed, 149 insertions(+) create mode 100644 source/connect/connection-targets.txt create mode 100644 source/includes/connect/atlas.php create mode 100644 source/includes/connect/direct-connection.php create mode 100644 source/includes/connect/replica-set.php diff --git a/snooty.toml b/snooty.toml index a77d00d6..8383cbf5 100644 --- a/snooty.toml +++ b/snooty.toml @@ -27,5 +27,6 @@ php-library = "MongoDB PHP Library" php-library = "MongoDB PHP Library" driver-short = "PHP library" +stable-api = "Stable API" mdb-server = "MongoDB Server" api = "https://www.mongodb.com/docs/php-library/current/reference" diff --git a/source/connect/connection-targets.txt b/source/connect/connection-targets.txt new file mode 100644 index 00000000..1047dc6d --- /dev/null +++ b/source/connect/connection-targets.txt @@ -0,0 +1,116 @@ +.. _php-connection-targets: + +========================== +Choose a Connection Target +========================== + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: connection string, URI, server, settings, client, stable api + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +In this guide, you can learn how to use a connection string and ``MongoDB\Client`` object +to connect to different types of MongoDB deployments. + +.. _php-connection-atlas: + +Atlas +----- + +To connect to a MongoDB deployment on Atlas, include the following elements +in your connection string: + +- URI of your Atlas cluster +- Database username +- Database user's password + +Then, pass your connection string to the ``MongoDB\Client`` constructor. + +When you connect to Atlas, we recommend using the {+stable-api+} client option to avoid +breaking changes when Atlas upgrades to a new version of {+mdb-server+}. +To learn more about the {+stable-api+} feature, see the :ref:`{+stable-api+} page +`. + +The following code shows how to use the {+driver-short+} to connect to an Atlas cluster. +The code also uses the ``serverApi`` option to specify a {+stable-api+} version. + +.. literalinclude:: /includes/connect/atlas.php + :copyable: true + :language: php + +.. tip:: + + Follow the :ref:`php-connection-string` step of the Quick Start + to retrieve your connection string. + +.. _php-connection-local: + +Local Deployments +----------------- + +To connect to a local MongoDB deployment, use ``localhost`` as the hostname. By +default, the ``mongod`` process runs on port 27017, though you can customize this for +your deployment. + +The following code shows how to use the {+driver-short+} to connect to a local MongoDB +deployment: + +.. literalinclude:: /includes/connect/client.php + :language: php + :copyable: true + +.. _php-connection-replica-set: + +Replica Sets +------------ + +To connect to a replica set, specify the hostnames (or IP addresses) and +port numbers of the replica set members in your connection string. + +If you aren't able to provide a full list of hosts in the replica set, you can +specify one or more of the hosts in the replica set and instruct the {+driver-short+} to +perform automatic discovery to find the others. To instruct the driver to perform +automatic discovery, choose one of the following actions: + +- Specify the name of the replica set as the value of the ``replicaSet`` parameter. +- Specify ``false`` as the value of the ``directConnection`` parameter. +- Specify more than one host in the replica set. + +In the following example, the driver uses a sample connection URI to connect to the +MongoDB replica set ``sampleRS``, which is running on port ``27017`` of three different +hosts, including ``host1``: + +.. literalinclude:: /includes/connect/replica-set.php + :language: php + :copyable: true + +Initialization +~~~~~~~~~~~~~~ + +To initialize a replica set, you must connect directly to a single member. To do so, +set the ``directConnection`` connection +option to ``true`` in the connection string. The following code example shows how to +set this connection option: + +.. literalinclude:: /includes/connect/direct-connection.php + :language: php + :copyable: true + +API Documentation +----------------- + +To learn more about using the ``MongoDB\Client`` class, +see the following API documentation: + +- :ref:`MongoDB\Client ` \ No newline at end of file diff --git a/source/includes/connect/atlas.php b/source/includes/connect/atlas.php new file mode 100644 index 00000000..29d219d5 --- /dev/null +++ b/source/includes/connect/atlas.php @@ -0,0 +1,19 @@ +"; + +// Create a MongoDB client with server API options +$client = new MongoDB\Client($uri, [], [ + 'serverApi' => new MongoDB\Driver\ServerApi('1') +]); + +// Ping the server to verify that the connection works +$admin = $client->admin; +$command = new MongoDB\Driver\Command(['ping' => 1]); +$result = $admin->command($command)->toArray(); + +echo json_encode($result), "\n"; +echo "Pinged your deployment. You successfully connected to MongoDB!\n"; + +?> diff --git a/source/includes/connect/direct-connection.php b/source/includes/connect/direct-connection.php new file mode 100644 index 00000000..fd896b3c --- /dev/null +++ b/source/includes/connect/direct-connection.php @@ -0,0 +1,7 @@ +:/?directConnection=true"; + +// Create a MongoDB client +$client = new MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/replica-set.php b/source/includes/connect/replica-set.php new file mode 100644 index 00000000..6086d425 --- /dev/null +++ b/source/includes/connect/replica-set.php @@ -0,0 +1,6 @@ + Date: Fri, 6 Sep 2024 14:17:20 -0400 Subject: [PATCH 028/149] tech review --- .../language-compatibility-table-php.rst | 78 +++---------------- .../mongodb-compatibility-table-php.rst | 57 -------------- 2 files changed, 12 insertions(+), 123 deletions(-) diff --git a/source/includes/language-compatibility-table-php.rst b/source/includes/language-compatibility-table-php.rst index 84e6a24e..50319621 100644 --- a/source/includes/language-compatibility-table-php.rst +++ b/source/includes/language-compatibility-table-php.rst @@ -1,33 +1,34 @@ .. sharedinclude:: dbx/compatibility-table-legend.rst - + .. list-table:: :header-rows: 1 :stub-columns: 1 :class: compatibility-large * - PHP Driver Versions + - PHP 8.4 - PHP 8.3 - PHP 8.2 - PHP 8.1 - PHP 8.0 - PHP 7.4 - PHP 7.3 - - PHP 7.2 - - PHP 7.1 - - PHP 7.0 - - PHP 5.6 - - PHP 5.5 - * - ext + lib 1.17 to 1.19 + * - ext + lib 1.20 + - ✓ - ✓ - ✓ - ✓ - ✓ - ✓ - - - - - - - + + * - ext + lib 1.17 to 1.19 + - ✓ + - ✓ + - ✓ + - ✓ + - ✓ - - @@ -39,10 +40,7 @@ - ✓ - ✓ - ✓ - - - - - - - - + * - ext + lib 1.15 [#PHP1.15-version-parity]_ - @@ -52,10 +50,6 @@ - ✓ - ✓ - ✓ - - - - - - - - * - ext 1.14 + lib 1.13 - @@ -65,10 +59,6 @@ - ✓ - ✓ - ✓ - - - - - - - - * - ext 1.13 + lib 1.12 - @@ -78,10 +68,6 @@ - ✓ - ✓ - ✓ - - - - - - - - * - ext 1.12 + lib 1.11 - @@ -91,10 +77,6 @@ - ✓ - ✓ - ✓ - - - - - - - - * - ext 1.11 + lib 1.10 - @@ -104,10 +86,6 @@ - ✓ - ✓ - ✓ - - ✓ - - - - - - * - ext 1.10 + lib 1.9 - @@ -117,10 +95,6 @@ - ✓ - ✓ - ✓ - - ✓ - - - - - - * - ext 1.9 + lib 1.8 - @@ -130,10 +104,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - - - * - ext 1.8 + lib 1.7 - @@ -143,10 +113,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - - - * - ext 1.7 + lib 1.6 - @@ -156,10 +122,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.6 + lib 1.5 - @@ -169,10 +131,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.5 + lib 1.4 - @@ -182,10 +140,6 @@ - - ✓ - ✓ - - ✓ - - ✓ - - ✓ - - ✓ * - ext 1.4 + lib 1.3 - @@ -195,10 +149,6 @@ - - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ * - ext 1.3 + lib 1.2 - @@ -207,8 +157,4 @@ - - - - - ✓ - - ✓ - - ✓ - - ✓ - ✓ \ No newline at end of file diff --git a/source/includes/mongodb-compatibility-table-php.rst b/source/includes/mongodb-compatibility-table-php.rst index 710b506e..82a9c271 100644 --- a/source/includes/mongodb-compatibility-table-php.rst +++ b/source/includes/mongodb-compatibility-table-php.rst @@ -15,9 +15,6 @@ - MongoDB 4.0 - MongoDB 3.6 - MongoDB 3.4 - - MongoDB 3.2 - - MongoDB 3.0 - - MongoDB 2.6 * - ext + lib 1.20 - ✓ @@ -29,9 +26,6 @@ - ✓ - - - - - - - - * - ext + lib 1.16 to 1.19 - ⊛ @@ -43,9 +37,6 @@ - ✓ - ✓ - - - - - - - * - ext + lib 1.15 [#PHP1.15-version-parity]_ - ⊛ @@ -57,9 +48,6 @@ - ✓ - ✓ - - - - - - - * - ext 1.14 + lib 1.13 - ⊛ @@ -71,9 +59,6 @@ - ✓ - ✓ - - - - - - - * - ext 1.13 + lib 1.12 - ⊛ @@ -85,9 +70,6 @@ - ✓ - ✓ - - - - - - - * - ext 1.12 + lib 1.11 - ⊛ @@ -99,9 +81,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - * - ext 1.11 + lib 1.10 - ⊛ @@ -113,9 +92,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - * - ext 1.10 + lib 1.9 - ⊛ @@ -127,9 +103,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - * - ext 1.9 + lib 1.8 - ⊛ @@ -141,9 +114,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - * - ext 1.8 + lib 1.7 - ⊛ @@ -155,9 +125,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - * - ext 1.7 + lib 1.6 - ⊛ @@ -169,9 +136,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - * - ext 1.6 + lib 1.5 - ⊛ @@ -183,9 +147,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - * - ext 1.5 + lib 1.4 - ⊛ @@ -197,9 +158,6 @@ - ✓ - ✓ - ✓ - - ✓ - - ✓ - - * - ext 1.4 + lib 1.3 - @@ -211,9 +169,6 @@ - - ✓ - ✓ - - ✓ - - ✓ - - ✓ * - ext 1.3 + lib 1.2 - @@ -225,9 +180,6 @@ - - - ✓ - - ✓ - - ✓ - - ✓ * - ext 1.2 + lib 1.1 - @@ -239,9 +191,6 @@ - - - ✓ - - ✓ - - ✓ - - ✓ * - ext 1.1 + lib 1.0 - @@ -253,9 +202,6 @@ - - - - - ✓ - - ✓ - - ✓ * - ext 1.0 - @@ -267,9 +213,6 @@ - - - - - - - ✓ - - ✓ .. [#PHP1.15-version-parity] Version 1.14 of the MongoDB PHP library has been skipped to restore version parity between the library and extension. From 017275cc460fb2f05e717f2694b67e380ba9056a Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 9 Sep 2024 10:14:21 -0400 Subject: [PATCH 029/149] DOCSP-41968: Update documents (#118) * DOCSP-41968: Update documents * snooty fix * edits --- source/includes/write/update.php | 45 ++++++ source/index.txt | 1 + source/write.txt | 11 ++ source/write/update.txt | 229 +++++++++++++++++++++++++++++++ 4 files changed, 286 insertions(+) create mode 100644 source/includes/write/update.php create mode 100644 source/write.txt create mode 100644 source/write/update.txt diff --git a/source/includes/write/update.php b/source/includes/write/update.php new file mode 100644 index 00000000..2aee12b7 --- /dev/null +++ b/source/includes/write/update.php @@ -0,0 +1,45 @@ +sample_restaurants->restaurants; +// end-db-coll + +// Updates the "name" value of a document from "Bagels N Buns" to "2 Bagels 2 Buns" +// start-update-one +$result = $collection->updateOne( + ['name' => 'Bagels N Buns'], + ['$set' => ['name' => '2 Bagels 2 Buns']] +); +// end-update-one + +// Updates the "cuisine" value of documents from "Pizza" to "Pasta" +// start-update-many +$result = $collection->updateMany( + ['cuisine' => 'Pizza'], + ['$set' => ['cuisine' => 'Pasta']] +); +// end-update-many + +// Updates the "borough" value of matching documents and inserts a document if none match +// start-update-options +$result = $collection->updateMany( + ['borough' => 'Manhattan'], + ['$set' => ['borough' => 'Manhattan (north)']], + ['upsert' => true] +); +// end-update-options + +// Updates the "name" value of matching documents and prints the number of updates +// start-update-result +$result = $collection->updateMany( + ['name' => 'Dunkin\' Donuts'], + ['$set' => ['name' => 'Dunkin\'']] +); +echo 'Modified documents: ' . $result->getModifiedCount(); +// end-update-result + diff --git a/source/index.txt b/source/index.txt index 38ff991f..7805e642 100644 --- a/source/index.txt +++ b/source/index.txt @@ -12,6 +12,7 @@ MongoDB PHP Library Get Started /read + /write /tutorial /upgrade /reference diff --git a/source/write.txt b/source/write.txt new file mode 100644 index 00000000..9053d5a4 --- /dev/null +++ b/source/write.txt @@ -0,0 +1,11 @@ +.. _php-write: + +===================== +Write Data to MongoDB +===================== + +.. toctree:: + :titlesonly: + :maxdepth: 1 + + /write/update \ No newline at end of file diff --git a/source/write/update.txt b/source/write/update.txt new file mode 100644 index 00000000..e07bde61 --- /dev/null +++ b/source/write/update.txt @@ -0,0 +1,229 @@ +.. _php-write-update: + +================ +Update Documents +================ + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: modify, change, bulk, code example + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to update +documents in a MongoDB collection. You can call the ``MongoDB\Collection::updateOne()`` +method to update a single document or the ``MongoDB\Collection::updateMany()`` +method to update multiple documents. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``collection`` variable: + +.. literalinclude:: /includes/write/update.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +Update Operations +----------------- + +You can perform update operations in MongoDB by using the following methods: + +- ``MongoDB\Collection::updateOne()``, which updates *the first document* that + matches the search criteria +- ``MongoDB\Collection::updateMany()``, which updates *all documents* that match + the search criteria + +Each update method requires the following parameters: + +- **Query filter** document: Specifies which documents to update. For + more information about query filters, see the + :manual:`Query Filter Documents section ` in + the {+mdb-server+} manual. + +- **Update** document: Specifies the **update operator**, or the kind of update to + perform, and the fields and values to change. For a list of update operators + and their usage, see the :manual:`Field Update Operators guide + ` in the {+mdb-server+} manual. + +Update One Document +~~~~~~~~~~~~~~~~~~~ + +The following example uses the ``updateOne()`` method to update the ``name`` +value of a document in the ``restaurants`` collection from ``'Bagels N Buns'`` +to ``'2 Bagels 2 Buns'``: + +.. literalinclude:: /includes/write/update.php + :start-after: start-update-one + :end-before: end-update-one + :language: php + :dedent: + +Update Many Documents +~~~~~~~~~~~~~~~~~~~~~ + +The following example uses the ``updateMany()`` method to update all documents +that have a ``cuisine`` value of ``'Pizza'``. After the update, the documents have +a ``cuisine`` value of ``'Pasta'``. + +.. literalinclude:: /includes/write/update.php + :start-after: start-update-many + :end-before: end-update-many + :language: php + :dedent: + +Customize the Update Operation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can modify the behavior of the ``updateOne()`` and ``updateMany()`` methods by +passing an array that specifies option values as a parameter. The following table +describes some options you can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``upsert`` + - | Specifies whether the update operation performs an upsert operation if no + documents match the query filter. For more information, see the :manual:`upsert + statement ` + in the {+mdb-server+} manual. + | Defaults to ``false``. + + * - ``bypassDocumentValidation`` + - | Specifies whether the update operation bypasses document validation. This lets you + update documents that don't meet the schema validation requirements, if any + exist. For more information about schema validation, see :manual:`Schema + Validation ` in the MongoDB + Server manual. + | Defaults to ``false``. + + * - ``collation`` + - | Specifies the kind of language collation to use when sorting + results. For more information, see :manual:`Collation ` + in the {+mdb-server+} manual. + + * - ``arrayFilters`` + - | Specifies which array elements an update applies to if the operation modifies + array fields. + + * - ``hint`` + - | Sets the index to scan for documents. + For more information, see the :manual:`hint statement ` + in the {+mdb-server+} manual. + + * - ``writeConcern`` + - | Sets the write concern for the operation. + For more information, see :manual:`Write Concern ` + in the {+mdb-server+} manual. + + * - ``let`` + - | Specifies a document with a list of values to improve operation readability. + Values must be constant or closed expressions that don't reference document + fields. For more information, see the :manual:`let statement + ` in the + {+mdb-server+} manual. + + * - ``comment`` + - | A comment to attach to the operation. For more information, see the :manual:`insert command + fields ` guide in the + {+mdb-server+} manual. + +The following example uses the ``updateMany()`` method to find all documents that +have ``borough`` value of ``'Manhattan'``. It then updates the ``borough`` value +in these documents to ``'Manhattan (north)'``. Because the ``upsert`` option is +set to ``true``, the {+php-library+} inserts a new document if the query filter doesn't +match any existing documents. + +.. literalinclude:: /includes/write/update.php + :start-after: start-update-options + :end-before: end-update-options + :language: php + :dedent: + +Return Value +~~~~~~~~~~~~ + +The ``updateOne()`` and ``updateMany()`` methods return an instance of +the ``MongoDB\UpdateResult`` class. This class contains the following +member functions: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Function + - Description + + * - ``getMatchedCount()`` + - | Returns the number of documents that matched the query filter, regardless of + how many were updated. + + * - ``getModifiedCount()`` + - | Returns the number of documents modified by the update operation. If an updated + document is identical to the original, it is not included in this + count. + + * - ``isAcknowledged()`` + - | Returns a boolean indicating whether the write operation was acknowledged. + + * - ``getUpsertedCount()`` + - | Returns the number of document that were upserted into the database. + + * - ``getUpsertedId()`` + - | Returns the ID of the document that was upserted in the database, if the driver + performed an upsert. + +The following example uses the ``updateMany()`` method to update the ``name`` field +of matching documents from ``'Dunkin' Donuts'`` to ``'Dunkin''``. It calls the +``getModifiedCount()`` member function to print the number of modified documents: + +.. io-code-block:: + :copyable: + + .. input:: /includes/write/update.php + :start-after: start-update-result + :end-before: end-update-result + :language: php + :dedent: + + .. output:: + :visible: false + + Modified documents: 206 + +Additional Information +---------------------- + +To learn more about creating query filters, see the :ref:`php-specify-query` guide. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::updateOne() <{+api+}/method/MongoDBCollection-updateOne>`__ +- `MongoDB\\Collection::updateMany() <{+api+}/method/MongoDBCollection-updateMany>`__ +- `MongoDB\\UpdateResult <{+api+}/class/MongoDBUpdateResult>`__ \ No newline at end of file From e5973dbdb8aa05abed4c32873ff5abd80bcf8064 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 9 Sep 2024 13:58:19 -0400 Subject: [PATCH 030/149] DOCSP-41967: Insert documents (#116) * DOCSP-41967: Insert documents * build * snooty * edit * JS feedback * JT feedback * JT feedback 2 --- snooty.toml | 1 - source/includes/write/insert.php | 37 +++++++ source/write.txt | 3 +- source/write/insert.txt | 172 +++++++++++++++++++++++++++++++ 4 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 source/includes/write/insert.php create mode 100644 source/write/insert.txt diff --git a/snooty.toml b/snooty.toml index 8383cbf5..de32d84e 100644 --- a/snooty.toml +++ b/snooty.toml @@ -24,7 +24,6 @@ toc_landing_pages = [ php-library = "MongoDB PHP Library" [constants] - php-library = "MongoDB PHP Library" driver-short = "PHP library" stable-api = "Stable API" diff --git a/source/includes/write/insert.php b/source/includes/write/insert.php new file mode 100644 index 00000000..3561a65e --- /dev/null +++ b/source/includes/write/insert.php @@ -0,0 +1,37 @@ +sample_restaurants->restaurants; +// end-db-coll + +// Inserts a document that stores a "name" value of "Mongo's Burgers" into the collection +// start-insert-one +$result = $collection->insertOne(['name' => 'Mongo\'s Burgers']); +// end-insert-one + +// Inserts documents representing restaurants into the collection +// start-insert-many +$restaurants = [ + ['name' => 'Mongo\'s Burgers'], + ['name' => 'Mongo\'s Pizza'] +]; + +$result = $collection->insertMany($restaurants); +// end-insert-many + +// Inserts multiple documents and instructs the insert operation to skip document-level validation +// start-modify +$docs = [ + ['name' => 'Mongo\'s Burgers'], + ['name' => 'Mongo\'s Pizza'], + ['name' => 'Mongo\'s Tacos'] +]; + +$result = $collection->insertMany($docs, ['bypassDocumentValidation' => true]); +// end-modify + diff --git a/source/write.txt b/source/write.txt index 9053d5a4..9352ca49 100644 --- a/source/write.txt +++ b/source/write.txt @@ -8,4 +8,5 @@ Write Data to MongoDB :titlesonly: :maxdepth: 1 - /write/update \ No newline at end of file + /write/insert + /write/update diff --git a/source/write/insert.txt b/source/write/insert.txt new file mode 100644 index 00000000..340c9410 --- /dev/null +++ b/source/write/insert.txt @@ -0,0 +1,172 @@ +.. _php-write-insert: + +================ +Insert Documents +================ + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, write, save, create + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to add +documents to a MongoDB collection by performing **insert operations**. + +An insert operation inserts one or more documents into a MongoDB collection. +You can perform an insert operation by using the following methods: + +- ``MongoDB\Collection::insertOne()`` method to insert a single document +- ``MongoDB\Collection::insertMany()`` method to insert one or more documents + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``collection`` variable: + +.. literalinclude:: /includes/write/insert.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +The ``_id`` Field +----------------- + +In a MongoDB collection, each document *must* contain an ``_id`` field +with a unique field value. + +MongoDB allows you to manage this field in two ways: + +- Set the ``_id`` field for each document yourself, ensuring each + value is unique. +- Let the driver automatically generate unique ``ObjectId`` + values for each document ``_id`` field. + +Unless you can guarantee uniqueness, we recommend +letting the driver automatically generate ``_id`` values. + +.. note:: + + Duplicate ``_id`` values violate unique index constraints, which + causes the driver to return a ``MongoDB\Driver\Exception\BulkWriteException`` + error. + +To learn more about the ``_id`` field, see the +:manual:`Unique Indexes ` guide in the {+mdb-server+} manual. + +To learn more about document structure and rules, see the +:manual:`Documents ` guide in the {+mdb-server+} manual. + +Insert One Document +------------------- + +To add a single document to a MongoDB collection, call the ``MongoDB\Collection::insertOne()`` +method and pass the document you want to add. + +The following example inserts a document into the ``restaurants`` collection: + +.. literalinclude:: /includes/write/insert.php + :language: php + :dedent: + :start-after: start-insert-one + :end-before: end-insert-one + +Insert Multiple Documents +------------------------- + +To add multiple documents to a MongoDB collection, call the ``MongoDB\Collection::insertMany()`` +method and pass an array that contains the list of documents you want to add. + +The following example inserts two documents into the ``restaurants`` collection: + +.. literalinclude:: /includes/write/insert.php + :language: php + :dedent: + :start-after: start-insert-many + :end-before: end-insert-many + +Modify Insert Behavior +---------------------- + +You can modify the behavior of the ``MongoDB\Collection::insertOne()`` and +``MongoDB\Collection::insertMany()`` methods by passing an array that specifies +option values as a parameter. The following table describes some options +you can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Field + - Description + + * - ``bypassDocumentValidation`` + - | If set to ``true``, allows the write operation to opt out of + :manual:`document-level validation `. + | Defaults to ``false``. + | **Type**: ``bool`` + + * - ``writeConcern`` + - | Sets the write concern for the operation. + | Defaults to the write concern of the namespace. + | **Type**: ``MongoDB\Driver\WriteConcern`` + + * - ``ordered`` + - | If set to ``true``, the operation stops inserting documents when one insert + fails. If ``false``, the operation continues to insert the remaining documents + when one insert fails. You cannot pass this option to the ``insertOne()`` method. + | Defaults to ``true``. + | **Type**: ``bool`` + + * - ``comment`` + - | A comment to attach to the operation. For more information, see the :manual:`insert command + fields ` guide in the + {+mdb-server+} manual. + | **Type**: any valid BSON type + +Example +~~~~~~~ + +The following code uses the ``insertMany()`` method to insert three new +documents into a collection. Because the ``bypassDocumentValidation`` field +is set to ``true`` in an options array, this +insert operation bypasses document-level validation: + +.. literalinclude:: /includes/write/insert.php + :language: php + :dedent: + :start-after: start-modify + :end-before: end-modify + +Additional Information +---------------------- + +.. TODO: + For runnable code examples of inserting documents with the {+php-library+}, see + :ref:`php-write`. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::insertOne() <{+api+}/method/MongoDBCollection-insertOne/>`__ +- `MongoDB\\Collection::insertMany() <{+api+}/method/MongoDBCollection-insertMany/>`__ \ No newline at end of file From a4b37961f91260771a9a8852218ad62c834773c0 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 9 Sep 2024 14:47:44 -0400 Subject: [PATCH 031/149] DOCSP-41980: Cursor guide (#110) * DOCSP-41980: Cursor guide * edits * code edits * output * vale fix * MM feedback * edit * fix code ex * edit * JT feedback --- snooty.toml | 1 + source/includes/read/cursor.php | 64 +++++++++++ source/read.txt | 1 + source/read/cursor.txt | 188 ++++++++++++++++++++++++++++++++ 4 files changed, 254 insertions(+) create mode 100644 source/includes/read/cursor.php create mode 100644 source/read/cursor.txt diff --git a/snooty.toml b/snooty.toml index de32d84e..711874cc 100644 --- a/snooty.toml +++ b/snooty.toml @@ -29,3 +29,4 @@ driver-short = "PHP library" stable-api = "Stable API" mdb-server = "MongoDB Server" api = "https://www.mongodb.com/docs/php-library/current/reference" +php-manual = "https://www.php.net/manual/en" diff --git a/source/includes/read/cursor.php b/source/includes/read/cursor.php new file mode 100644 index 00000000..7747a52c --- /dev/null +++ b/source/includes/read/cursor.php @@ -0,0 +1,64 @@ +sample_restaurants->restaurants; +// end-db-coll + +// Iterates over and prints all documents that have a "name" value of "Dunkin' Donuts" +// start-cursor-iterate +$cursor = $collection->find(['name' => 'Dunkin\' Donuts']); +foreach ($cursor as $doc) { + echo json_encode($doc) . PHP_EOL; +} +// end-cursor-iterate + +// Retrieves and prints the first document stored in the cursor +// start-cursor-first +$cursor = $collection->find(['name' => 'Dunkin\' Donuts']); +$cursor->rewind(); +echo json_encode($cursor->current()); +// end-cursor-first + +// Converts the documents stored in a cursor to an array +// start-cursor-array +$cursor = $collection->find(['name' => 'Dunkin\' Donuts']); +$array_results = $cursor->toArray(); +// end-cursor-array + +// Creates a collection with a maximum size and inserts documents representing vegetables +// start-capped-coll +$db = $client->db; +$create_coll = $db->createCollection( + 'vegetables', + ['capped' => true, 'size' => 1024 * 1024] +); + +$vegetables = [ + ['name' => 'cauliflower'], + ['name' => 'zucchini'] +]; + +$collection = $db->vegetables; +$result = $collection->insertMany($vegetables); +// end-capped-coll + +// Iterates over the initial query results and continues iterating until three documents are stored in the cursor +// by using a tailable cursor +// start-tailable +$cursor = $collection->find([], ['cursorType' => MongoDB\Operation\Find::TAILABLE]); +$cursor->rewind(); + +$docs_found = 0; +while ($docs_found < 3) { + if ($cursor->valid()) { + $doc = $cursor->current(); + echo json_encode($doc) . PHP_EOL; + $docs_found++; + } + $cursor->next(); +} +// end-tailable diff --git a/source/read.txt b/source/read.txt index a45c2a82..0b6f6c78 100644 --- a/source/read.txt +++ b/source/read.txt @@ -10,6 +10,7 @@ Read Data from MongoDB /read/retrieve /read/project + /read/cursor /read/count /read/specify-documents-to-return /read/specify-a-query diff --git a/source/read/cursor.txt b/source/read/cursor.txt new file mode 100644 index 00000000..1fb36fb6 --- /dev/null +++ b/source/read/cursor.txt @@ -0,0 +1,188 @@ +.. _php-cursors: + +========================= +Access Data From a Cursor +========================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: read, results, code example + +Overview +-------- + +In this guide, you can learn how to access data from a **cursor** by using the +{+php-library+}. + +A cursor is a mechanism that returns the results of a read operation in iterable +batches. Cursors reduce both memory consumption and the number of server requests +by holding only a subset of documents at any given time, rather than returning all +documents at once. + +Whenever the {+php-library+} performs a read operation by using the ``MongoDB\Collection::find()`` +method, it returns the matching documents in a ``MongoDB\Driver\Cursor`` instance. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``$collection`` variable: + +.. literalinclude:: /includes/read/cursor.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +.. _php-cursors-iterate: + +Access Cursor Contents Iteratively +---------------------------------- + +The ``MongoDB\Driver\Cursor`` class implements the ``Iterator`` interface, so you +can use a ``foreach`` loop to iterate through its contents. + +The following example uses the ``MongoDB\Collection::find()`` method to retrieve all documents +in which the ``name`` field value is ``'Dunkin' Donuts'``. It then prints each document from the +cursor returned by the ``find()`` method: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/cursor.php + :start-after: start-cursor-iterate + :end-before: end-cursor-iterate + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},..."name":"Dunkin' Donuts","restaurant_id":"40379573"} + {"_id":{"$oid":"..."},..."name":"Dunkin' Donuts","restaurant_id":"40363098"} + {"_id":{"$oid":"..."},..."name":"Dunkin' Donuts","restaurant_id":"40395071"} + ... + +Retrieve Documents Individually +------------------------------- + +To retrieve an individual document from a cursor, call the ``current()`` method on +a ``MongoDB\Driver\Cursor`` instance. This method returns the document that the cursor +initially points to. You can continue to advance the cursor by calling the ``next()`` +method, which instructs the cursor to point to the next retrieved document. + +The following example finds all documents in which the ``name`` field value is +``'Dunkin' Donuts'``. Then, it prints the first retrieved document by calling the +``current()`` method on a cursor: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/cursor.php + :start-after: start-cursor-first + :end-before: end-cursor-first + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},..."name":"Dunkin' Donuts","restaurant_id":"40379573"} + +Retrieve All Documents +---------------------- + +.. warning:: + + If the number and size of documents returned by your query exceeds available + application memory, your program will crash. If you expect a large result + set, :ref:`access your cursor iteratively `. + +To retrieve all documents from a cursor, convert the cursor into an array by using +either of the following methods: + +- ``MongoDB\\Driver\\Cursor::toArray()``: Call on a ``MongoDB\Driver\Cursor`` object +- ``iterator_to_array()``: Pass a ``MongoDB\Driver\Cursor`` object as a parameter + +The following example calls the ``toArray()`` method on a cursor to store its results +in an array: + +.. literalinclude:: /includes/read/cursor.php + :language: php + :dedent: + :start-after: start-cursor-array + :end-before: end-cursor-array + +Tailable Cursors +---------------- + +When querying on a :manual:`capped collection `, you +can use a **tailable cursor** that remains open after the client exhausts the +results in a cursor. To create a tailable cursor, set the ``cursorType`` option to +``MongoDB\Operation\Find::TAILABLE`` in an array. Then, pass the array as an options +parameter to the ``MongoDB\Collection::find()`` method. + +For example, you can create a capped collection called ``vegetables`` that stores +documents representing vegetables, as shown in the following code: + +.. literalinclude:: /includes/read/cursor.php + :language: php + :dedent: + :start-after: start-capped-coll + :end-before: end-capped-coll + +The following code uses a tailable cursor to retrieve all documents in the ``vegetables`` +collection. After the cursor is exhausted, it remains open until retrieving three documents: + +.. io-code-block:: + :copyable: + + .. input:: /includes/read/cursor.php + :start-after: start-tailable + :end-before: end-tailable + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":{"$oid":"..."},"name":"cauliflower"} + {"_id":{"$oid":"..."},"name":"zucchini"} + +If you insert another document into the ``vegetables`` collection, the preceding code prints +the new document and closes the ``while`` loop. + +To learn more about tailable cursors, see :manual:`Tailable Cursors +` in the {+mdb-server+} manual. + +Additional Information +---------------------- + +To learn more about read operations, see the :ref:`php-retrieve` guide. + +To learn more about cursors, see the following pages in the PHP manual: + +- `MongoDB\\Driver\\Cursor <{+php-manual+}/class.mongodb-driver-cursor.php>`__ +- `MongoDB\\Driver\\Cursor::current() <{+php-manual+}/mongodb-driver-cursor.current.php>`__ +- `MongoDB\\Driver\\Cursor::toArray() <{+php-manual+}/mongodb-driver-cursor.toarray.php>`__ +- `iterator_to_array() <{+php-manual+}/function.iterator-to-array.php>`__ + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about the ``find()`` method, see the API documentation for +`MongoDB\\Collection::find() <{+api+}/method/MongoDBCollection-find/>`__. \ No newline at end of file From f7d2584fcfeaab7fa07e031fb149136002b834a9 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 9 Sep 2024 15:03:28 -0400 Subject: [PATCH 032/149] DOCSP-41988: Aggregation (#115) * DOCSP-41988: Aggregation * toc * edits * code edit * JS feedback * dev center * JM feedback * explain api link * JM feedback 2 --- source/aggregation.txt | 205 +++++++++++++++++++++++ source/includes/aggregation.php | 40 +++++ source/includes/read/limit-skip-sort.php | 8 +- source/includes/read/project.php | 6 +- source/includes/read/retrieve.php | 6 +- source/includes/read/specify-queries.php | 14 +- source/index.txt | 1 + 7 files changed, 263 insertions(+), 17 deletions(-) create mode 100644 source/aggregation.txt create mode 100644 source/includes/aggregation.php diff --git a/source/aggregation.txt b/source/aggregation.txt new file mode 100644 index 00000000..1a677c95 --- /dev/null +++ b/source/aggregation.txt @@ -0,0 +1,205 @@ +.. _php-aggregation: + +==================================== +Transform Your Data with Aggregation +==================================== + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, transform, computed, pipeline + :description: Learn how to use the PHP library to perform aggregation operations. + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. TODO: + .. toctree:: + :titlesonly: + :maxdepth: 1 + + /aggregation/aggregation-tutorials + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to perform +**aggregation operations**. + +Aggregation operations process data in your MongoDB collections and +return computed results. The MongoDB Aggregation framework, which is +part of the Query API, is modeled on the concept of data processing +pipelines. Documents enter a pipeline that contains one or more stages, +and this pipeline transforms the documents into an aggregated result. + +An aggregation operation is similar to a car factory. A car factory has +an assembly line, which contains assembly stations with specialized +tools to do specific jobs, like drills and welders. Raw parts enter the +factory, and then the assembly line transforms and assembles them into a +finished product. + +The **aggregation pipeline** is the assembly line, **aggregation stages** are the +assembly stations, and **operator expressions** are the +specialized tools. + +Aggregation Versus Find Operations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use find operations to perform the following actions: + +- Select which documents to return +- Select which fields to return +- Sort the results + +You can use aggregation operations to perform the following actions: + +- Run find operations +- Rename fields +- Calculate fields +- Summarize data +- Group values + +Limitations +~~~~~~~~~~~ + +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. + + .. important:: $graphLookup Exception + + The :manual:`$graphLookup + ` stage has a strict + memory limit of 100 megabytes and ignores the ``allowDiskUse`` option. + +.. _php-aggregation-example: + +Aggregation Example +------------------- + +.. note:: + + 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. + +To perform an aggregation, pass an array containing the pipeline stages to +the ``MongoDB\Collection::aggregate()`` method. + +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'`` + +- :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: + + .. input:: /includes/aggregation.php + :start-after: start-match-group + :end-before: end-match-group + :language: php + :dedent: + + .. output:: + :visible: false + + {"_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} + +Explain an Aggregation +~~~~~~~~~~~~~~~~~~~~~~ + +To view information about how MongoDB executes your operation, you can +instruct the MongoDB query planner to **explain** it. When MongoDB explains +an operation, it returns **execution plans** and performance statistics. +An execution plan is a potential way in which MongoDB can complete an operation. +When you instruct MongoDB to explain an operation, it returns both the +plan MongoDB executed and any rejected execution plans. + +To explain an aggregation operation, construct a ``MongoDB\Operation\Aggregate`` object +and pass the database, collection, and pipeline stages as parameters. Then, pass the +``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`: + +.. io-code-block:: + :copyable: + + .. input:: /includes/aggregation.php + :start-after: start-explain + :end-before: end-explain + :language: php + :dedent: + + .. output:: + :visible: false + + {"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":{ + ... } + +Additional Information +---------------------- + +To view a tutorial that uses the {+php-library+} to create complex aggregation +pipelines, see `Complex Aggregation Pipelines with Vanilla PHP and MongoDB +`__ +in the MongoDB Developer Center. + +MongoDB Server Manual +~~~~~~~~~~~~~~~~~~~~~ + +To learn more about the topics discussed in this guide, see the following +pages in the {+mdb-server+} manual: + +- To view a full list of expression operators, see :manual:`Aggregation + Operators `. + +- To learn about assembling an aggregation pipeline and to view examples, see + :manual:`Aggregation Pipeline `. + +- To learn more about creating pipeline stages, see :manual:`Aggregation + Stages `. + +- To learn more about explaining MongoDB operations, see + :manual:`Explain Output ` and + :manual:`Query Plans `. + +.. TODO: + Aggregation Tutorials + ~~~~~~~~~~~~~~~~~~~~~ + +.. To view step-by-step explanations of common aggregation tasks, see +.. :ref:`php-aggregation-tutorials-landing`. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about the methods discussed in this guide, see the +following API documentation: + +- `MongoDB\\Collection::aggregate() <{+api+}/method/MongoDBCollection-aggregate/>`__ +- `MongoDB\\Collection::explain() <{+api+}/method/MongoDBCollection-explain/>`__ diff --git a/source/includes/aggregation.php b/source/includes/aggregation.php new file mode 100644 index 00000000..e2cfa914 --- /dev/null +++ b/source/includes/aggregation.php @@ -0,0 +1,40 @@ +sample_restaurants->restaurants; + +// Retrieves documents with a cuisine value of "Bakery", groups them by "borough", and +// counts each borough's matching documents +// start-match-group +$pipeline = [ + ['$match' => ['cuisine' => 'Bakery']], + ['$group' => ['_id' => '$borough', 'count' => ['$sum' => 1]]], +]; + +$cursor = $collection->aggregate($pipeline); + +foreach ($cursor as $doc) { + echo json_encode($doc) , PHP_EOL; +} +// end-match-group + +// Performs the same aggregation operation as above but asks MongoDB to explain it +// start-explain +$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; +// end-explain + diff --git a/source/includes/read/limit-skip-sort.php b/source/includes/read/limit-skip-sort.php index 3ab8a16f..8beec933 100644 --- a/source/includes/read/limit-skip-sort.php +++ b/source/includes/read/limit-skip-sort.php @@ -17,7 +17,7 @@ ); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-limit @@ -29,7 +29,7 @@ ); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-sort @@ -41,7 +41,7 @@ ); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-skip @@ -56,7 +56,7 @@ $cursor = $collection->find(['cuisine' => 'Italian'], $options); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-limit-sort-skip diff --git a/source/includes/read/project.php b/source/includes/read/project.php index 1e7c42f3..3f63d93b 100644 --- a/source/includes/read/project.php +++ b/source/includes/read/project.php @@ -21,7 +21,7 @@ $cursor = $collection->find(['name' => 'Emerald Pub'], $options); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-project-include @@ -39,7 +39,7 @@ $cursor = $collection->find(['name' => 'Emerald Pub'], $options); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-project-include-without-id @@ -54,6 +54,6 @@ $cursor = $collection->find(['name' => 'Emerald Pub'], $options); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-project-exclude diff --git a/source/includes/read/retrieve.php b/source/includes/read/retrieve.php index fbd64a0d..ed086984 100644 --- a/source/includes/read/retrieve.php +++ b/source/includes/read/retrieve.php @@ -11,7 +11,7 @@ // Finds one document with a "name" value of "LinkedIn" // start-find-one $document = $collection->findOne(['name' => 'LinkedIn']); -echo json_encode($document) . "\n"; +echo json_encode($document) , "\n"; // end-find-one // Finds documents with a "founded_year" value of 1970 @@ -22,7 +22,7 @@ // Prints documents with a "founded_year" value of 1970 // start-cursor foreach ($results as $doc) { - echo json_encode($doc) . "\n"; + echo json_encode($doc) , "\n"; } // end-cursor @@ -34,6 +34,6 @@ ); foreach ($results as $doc) { - echo json_encode($doc) . "\n"; + echo json_encode($doc) , "\n"; } // end-modify diff --git a/source/includes/read/specify-queries.php b/source/includes/read/specify-queries.php index 3e3c07cb..df7e1c11 100644 --- a/source/includes/read/specify-queries.php +++ b/source/includes/read/specify-queries.php @@ -50,7 +50,7 @@ // start-find-exact $cursor = $collection->find(['color' => 'yellow']); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-find-exact @@ -58,7 +58,7 @@ // start-find-all $cursor = $collection->find([]); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-find-all @@ -66,7 +66,7 @@ // start-find-comparison $cursor = $collection->find(['rating' => ['$gt' => 2]]); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-find-comparison @@ -79,7 +79,7 @@ ] ]); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-find-logical @@ -87,7 +87,7 @@ // start-find-array $cursor = $collection->find(['type' => ['$size' => 2]]); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-find-array @@ -95,7 +95,7 @@ // start-find-element $cursor = $collection->find(['color' => ['$exists' => true]]); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-find-element @@ -103,6 +103,6 @@ // start-find-evaluation $cursor = $collection->find(['name' => ['$regex' => 'p{2,}']]); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc) , PHP_EOL; } // end-find-evaluation diff --git a/source/index.txt b/source/index.txt index 7805e642..72d8b53b 100644 --- a/source/index.txt +++ b/source/index.txt @@ -13,6 +13,7 @@ MongoDB PHP Library Get Started /read /write + /aggregation /tutorial /upgrade /reference From 3cae05879305c8b3b0f26be4291f35f422db0d0b Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 5 Sep 2024 15:52:23 -0400 Subject: [PATCH 033/149] DOCSP-41983: indexes landing pg --- .../usage-examples/index-code-examples.php | 79 ++++++ .../usage-examples/sample-app-intro.rst | 10 + source/includes/usage-examples/sample-app.php | 12 + source/index.txt | 1 + source/indexes.txt | 260 ++++++++++++++++++ 5 files changed, 362 insertions(+) create mode 100644 source/includes/usage-examples/index-code-examples.php create mode 100644 source/includes/usage-examples/sample-app-intro.rst create mode 100644 source/includes/usage-examples/sample-app.php create mode 100644 source/indexes.txt diff --git a/source/includes/usage-examples/index-code-examples.php b/source/includes/usage-examples/index-code-examples.php new file mode 100644 index 00000000..5dcae071 --- /dev/null +++ b/source/includes/usage-examples/index-code-examples.php @@ -0,0 +1,79 @@ +'); +$collection = $client->->; + +// start-single-field +$result = $collection->createIndex(['' => 1]); +// end-single-field + +// start-compound +$indexName = $collection->createIndex( + ['' => 1, '' => 1] +); +// end-compound + +// start-multikey +$result = $collection->createIndex(['' => 1]); +// end-multikey + +// start-search-create +$result = $collection->createSearchIndex( + ['mappings' => ['dynamic' => true]], + ['name' => ''] +); +// end-search-create + +// start-search-list +foreach ($collection->listIndexes() as $indexInfo) { + var_dump($indexInfo); +} +// end-search-list + +// start-search-update +$result = $collection->updateSearchIndex( + ['name' => ''], + ['mappings' => ['dynamic' => true]], + ); +// end-search-update + +// start-search-delete +$result = $collection->dropIndex(''); +// end-search-delete + +// start-text +$result = $collection->createIndex(['' => 'text']); +// end-text + +// start-geo +$result = $collection->createIndex( + [ '' => '2dsphere'], ['name' => ''] +); +// end-geo + +// start-unique +$result = $collection->createIndex(['' => 1], ['unique' => true]); +// end-unique + +// start-wildcard +$result = $collection->createIndex(['$**' => 1]); +// end-wildcard + +// start-clustered +$options = [ + 'clusteredIndex' => [ + 'key' => ['_id' => 1], + 'unique' => true + ] +]; + +$database->createCollection('', $options); +// end-clustered + +// start-remove +$result = $collection->dropIndex(''); +// end-remove \ No newline at end of file diff --git a/source/includes/usage-examples/sample-app-intro.rst b/source/includes/usage-examples/sample-app-intro.rst new file mode 100644 index 00000000..cee5f2d7 --- /dev/null +++ b/source/includes/usage-examples/sample-app-intro.rst @@ -0,0 +1,10 @@ +Sample Application +~~~~~~~~~~~~~~~~~~ + +You can use the following sample application to test the code examples on this +page. To use the sample application, perform the following steps: + +1. Ensure you have the {+php-library+} installed in your project. +#. Copy the following code and paste it into a new ``.php`` file. +#. Copy a code example from this page and paste it on the specified + lines in the file. diff --git a/source/includes/usage-examples/sample-app.php b/source/includes/usage-examples/sample-app.php new file mode 100644 index 00000000..140b2b2b --- /dev/null +++ b/source/includes/usage-examples/sample-app.php @@ -0,0 +1,12 @@ +'); +$collection = $client->->; + +// Start example code here + +// End example code here diff --git a/source/index.txt b/source/index.txt index 72d8b53b..b4b4841a 100644 --- a/source/index.txt +++ b/source/index.txt @@ -14,6 +14,7 @@ MongoDB PHP Library /read /write /aggregation + /indexes /tutorial /upgrade /reference diff --git a/source/indexes.txt b/source/indexes.txt new file mode 100644 index 00000000..f41bcf6e --- /dev/null +++ b/source/indexes.txt @@ -0,0 +1,260 @@ +.. _php-indexes: + +================================= +Optimize Queries by Using Indexes +================================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :description: Learn how to use indexes by using the MongoDB PHP Library. + :keywords: query, optimization, efficiency, usage example, code example + +.. .. toctree:: +.. :titlesonly: +.. :maxdepth: 1 +.. +.. /work-with-indexes + +Overview +-------- + +On this page, you can see copyable code examples that show how to manage +different types of indexes by using the {+php-library+}. + +.. .. tip:: +.. +.. To learn more about working with indexes, see the :ref:`php-work-indexes` +.. guide. To learn more about any of the indexes shown on this page, see the link +.. provided in each section. + +To use an example from this page, copy the code example into the +:ref:`sample application ` or your own application. +Be sure to replace all placeholders in the code examples, such as +````, with the relevant values for your MongoDB +deployment. + +.. _php-index-sample: + +.. include:: /includes/usage-examples/sample-app-intro.rst + +.. literalinclude:: /includes/usage-examples/sample-app.php + :language: php + :copyable: + :linenos: + :emphasize-lines: 10-12 + +Single Field Index +------------------ + +The following example creates an ascending index on the specified field: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-single-field + :end-before: end-single-field + :language: php + :copyable: + :dedent: + +.. To learn more about single field indexes, see the +.. :ref:`php-single-field-index` guide. + +Compound Index +-------------- + +The following example creates a compound index on the specified fields: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-compound + :end-before: end-compound + :language: php + :copyable: + :dedent: + +.. To learn more about compound indexes, see the :ref:`php-compound-index` guide. + +Multikey Index +-------------- + +The following example creates a multikey index on the specified array-valued field: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-multikey + :end-before: end-multikey + :language: php + :copyable: + :dedent: + +.. TODO To learn more about multikey indexes, see the :ref:`php-multikey-index` +.. guide. + +Geospatial Index +---------------- + +The following example creates a 2dsphere index on the specified field +that has GeoJSON object values: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-geo + :end-before: end-geo + :language: php + :copyable: + :dedent: + +.. TODO: To learn more about geospatial indexes, see the :ref:`php-geospatial-index` +.. guide. + +Unique Index +------------ + +The following example creates a unique index on the specified field: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-unique + :end-before: end-unique + :language: php + :copyable: + :dedent: + +.. TODO: To learn more about unique indexes, see the :ref:`php-unique-index` +.. guide. + +Wildcard Index +-------------- + +The following example creates a wildcard index in the specified collection: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-wildcard + :end-before: end-wildcard + :language: php + :copyable: + :dedent: + +.. TODO: To learn more about wildcard indexes, see the :ref:`php-wildcard-index` +.. guide. + +Clustered Index +--------------- + +You can create a clustered index when creating a new collection in a +specified database. The following example creates a new collection with a +clustered index on the ``_id`` field: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-clustered + :end-before: end-clustered + :language: php + :copyable: + :dedent: + +.. TODO: To learn more about clustered indexes, see the :ref:`php-clustered-index` +.. guide. + +Atlas Search Index Management +----------------------------- + +The following sections contain code examples that describe how to manage +:atlas:`Atlas Search indexes `. + +.. To learn more about Atlas Search indexes, see the :ref:`php-atlas-search-index` +.. guide. + +Create Search Index +~~~~~~~~~~~~~~~~~~~ + +The following example creates an Atlas Search index on the specified field: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-search-create + :end-before: end-search-create + :language: php + :copyable: + :dedent: + +.. To learn more about creating search indexes, see the +.. :ref:`php-atlas-search-index-create` guide. + +List Search Indexes +~~~~~~~~~~~~~~~~~~~ + +The following example prints a list of Atlas Search indexes in the specified collection: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-search-list + :end-before: end-search-list + :language: php + :copyable: + :dedent: + +.. To learn more about listing search indexes, see the :ref:`php-atlas-search-index-list` +.. guide. + +Update Search Indexes +~~~~~~~~~~~~~~~~~~~~~ + +The following example updates an existing Atlas Search index with the specified +new index definition: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-search-update + :end-before: end-search-update + :language: php + :copyable: + :dedent: + +.. To learn more about updating search indexes, see the :ref:`php-atlas-search-index-update` +.. guide. + +Delete Search Indexes +~~~~~~~~~~~~~~~~~~~~~ + +The following example deletes an Atlas Search index with the specified name: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-search-delete + :end-before: end-search-delete + :language: php + :copyable: + :dedent: + +.. To learn more about deleting search indexes, see the :ref:`php-atlas-search-index-drop` +.. guide. + +Text Index +---------- + +The following example creates a text index on the specified string field: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-text + :end-before: end-text + :language: php + :copyable: + :dedent: + +.. TODO: To learn more about text indexes, see the :ref:`php-text-index` +.. guide. + +Delete an Index +--------------- + +The following example deletes an index with the specified name: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-remove + :end-before: end-remove + :language: php + :copyable: + :dedent: + +.. TODO: To learn more about removing indexes, see :ref:`php-indexes-remove` +.. in the Work with Indexes guide. \ No newline at end of file From d65dae93072c699b4ec33c813d7e25e3e3fe021b Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 5 Sep 2024 15:58:23 -0400 Subject: [PATCH 034/149] wip --- .../usage-examples/index-code-examples.php | 8 +++++++- source/indexes.txt | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/source/includes/usage-examples/index-code-examples.php b/source/includes/usage-examples/index-code-examples.php index 5dcae071..c767d55c 100644 --- a/source/includes/usage-examples/index-code-examples.php +++ b/source/includes/usage-examples/index-code-examples.php @@ -29,7 +29,7 @@ // end-search-create // start-search-list -foreach ($collection->listIndexes() as $indexInfo) { +foreach ($collection->listSearchIndexes() as $indexInfo) { var_dump($indexInfo); } // end-search-list @@ -74,6 +74,12 @@ $database->createCollection('', $options); // end-clustered +// start-list +foreach ($collection->listIndexes() as $indexInfo) { + var_dump($indexInfo); +} +// end-list + // start-remove $result = $collection->dropIndex(''); // end-remove \ No newline at end of file diff --git a/source/indexes.txt b/source/indexes.txt index f41bcf6e..4c8c0c66 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -186,7 +186,8 @@ The following example creates an Atlas Search index on the specified field: List Search Indexes ~~~~~~~~~~~~~~~~~~~ -The following example prints a list of Atlas Search indexes in the specified collection: +The following example prints a list of Atlas Search indexes in the +specified collection: .. literalinclude:: /includes/usage-examples/index-code-examples.php :start-after: start-search-list @@ -244,6 +245,19 @@ The following example creates a text index on the specified string field: .. TODO: To learn more about text indexes, see the :ref:`php-text-index` .. guide. +List Indexes +------------ + +The following example prints a list indexes in the +specified collection: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-list + :end-before: end-list + :language: php + :copyable: + :dedent: + Delete an Index --------------- From 2477f397db551f496c26e874714c056e750b2c69 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 5 Sep 2024 15:59:11 -0400 Subject: [PATCH 035/149] wip --- source/indexes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/indexes.txt b/source/indexes.txt index 4c8c0c66..de22313e 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -248,7 +248,7 @@ The following example creates a text index on the specified string field: List Indexes ------------ -The following example prints a list indexes in the +The following example prints a list of indexes in the specified collection: .. literalinclude:: /includes/usage-examples/index-code-examples.php From 4abb6ded78be56c9b7d2c2706ef7fa6e7523f086 Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 6 Sep 2024 10:52:04 -0400 Subject: [PATCH 036/149] MM PR fixes 1 --- source/indexes.txt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/source/indexes.txt b/source/indexes.txt index de22313e..349cab82 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -70,7 +70,8 @@ The following example creates an ascending index on the specified field: Compound Index -------------- -The following example creates a compound index on the specified fields: +The following example creates a compound index of two ascending indexes +on the specified fields: .. literalinclude:: /includes/usage-examples/index-code-examples.php :start-after: start-compound @@ -84,7 +85,8 @@ The following example creates a compound index on the specified fields: Multikey Index -------------- -The following example creates a multikey index on the specified array-valued field: +The following example creates an ascending multikey index on the +specified array-valued field: .. literalinclude:: /includes/usage-examples/index-code-examples.php :start-after: start-multikey @@ -115,7 +117,8 @@ that has GeoJSON object values: Unique Index ------------ -The following example creates a unique index on the specified field: +The following example creates an ascending unique index on the specified +field: .. literalinclude:: /includes/usage-examples/index-code-examples.php :start-after: start-unique @@ -130,7 +133,8 @@ The following example creates a unique index on the specified field: Wildcard Index -------------- -The following example creates a wildcard index in the specified collection: +The following example creates an ascending wildcard index on the +collection: .. literalinclude:: /includes/usage-examples/index-code-examples.php :start-after: start-wildcard @@ -146,8 +150,8 @@ Clustered Index --------------- You can create a clustered index when creating a new collection in a -specified database. The following example creates a new collection with a -clustered index on the ``_id`` field: +specified database. The following example creates a new collection with an +ascending clustered index on the ``_id`` field: .. literalinclude:: /includes/usage-examples/index-code-examples.php :start-after: start-clustered From e227a7fdb3b62954dc39819fb5a0c0ef8096606a Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 10 Sep 2024 10:29:42 -0400 Subject: [PATCH 037/149] JM tech review 1 --- source/includes/usage-examples/sample-app.php | 6 +++--- source/indexes.txt | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/includes/usage-examples/sample-app.php b/source/includes/usage-examples/sample-app.php index 140b2b2b..f9d2cb83 100644 --- a/source/includes/usage-examples/sample-app.php +++ b/source/includes/usage-examples/sample-app.php @@ -2,10 +2,10 @@ require __DIR__ . '/../vendor/autoload.php'; -use MongoDB\Client; +$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your Atlas URI that connects to the sample dataset'); +$client = new MongoDB\Client($uri); -$client = new Client(''); -$collection = $client->->; +$collection = $client->selectCollection('', ''); // Start example code here diff --git a/source/indexes.txt b/source/indexes.txt index 349cab82..b1c3155d 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -38,9 +38,10 @@ different types of indexes by using the {+php-library+}. To use an example from this page, copy the code example into the :ref:`sample application ` or your own application. -Be sure to replace all placeholders in the code examples, such as -````, with the relevant values for your MongoDB -deployment. +Make sure to set the ``MONGODB_URI`` environment variable to the +connection string for your MongoDB deployment, and replace the +```` and ```` placeholders with values for your +target namespace. .. _php-index-sample: From b18b221e2708f84844e20b871f8efc93a4e5f656 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 10 Sep 2024 11:02:34 -0400 Subject: [PATCH 038/149] JM tech review 1 --- .../usage-examples/index-code-examples.php | 52 ++++++--- source/indexes.txt | 108 +++++++++++------- 2 files changed, 98 insertions(+), 62 deletions(-) diff --git a/source/includes/usage-examples/index-code-examples.php b/source/includes/usage-examples/index-code-examples.php index c767d55c..0bea50b0 100644 --- a/source/includes/usage-examples/index-code-examples.php +++ b/source/includes/usage-examples/index-code-examples.php @@ -2,13 +2,21 @@ require __DIR__ . '/../vendor/autoload.php'; -use MongoDB\Client; +$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your Atlas URI that connects to the sample dataset'); +$client = new MongoDB\Client($uri); -$client = new Client(''); -$collection = $client->->; +$database = $client->sample_db; +$collection = $database->sample_coll; + +// start-to-json +function toJSON(object $document): string +{ + return MongoDB\BSON\Document::fromPHP($document)->toRelaxedExtendedJSON(); +} +// end-to-json // start-single-field -$result = $collection->createIndex(['' => 1]); +$indexName = $collection->createIndex(['' => 1]); // end-single-field // start-compound @@ -18,11 +26,11 @@ // end-compound // start-multikey -$result = $collection->createIndex(['' => 1]); +$indexName = $collection->createIndex(['' => 1]); // end-multikey // start-search-create -$result = $collection->createSearchIndex( +$indexName = $collection->createSearchIndex( ['mappings' => ['dynamic' => true]], ['name' => ''] ); @@ -30,37 +38,45 @@ // start-search-list foreach ($collection->listSearchIndexes() as $indexInfo) { - var_dump($indexInfo); + echo toJSON($indexInfo) . PHP_EOL; } // end-search-list // start-search-update -$result = $collection->updateSearchIndex( - ['name' => ''], - ['mappings' => ['dynamic' => true]], +$collection->updateSearchIndex( + ['name' => ''], + ['mappings' => [ + 'dynamic' => false, + 'fields' => [ + '' => [ + 'type' => 'string', + 'analyzer' => 'lucene.standard' + ] + ] + ]] ); // end-search-update // start-search-delete -$result = $collection->dropIndex(''); +$collection->dropSearchIndex(''); // end-search-delete // start-text -$result = $collection->createIndex(['' => 'text']); +$indexName = $collection->createIndex(['' => 'text']); // end-text // start-geo -$result = $collection->createIndex( - [ '' => '2dsphere'], ['name' => ''] +$indexName = $collection->createIndex( + [ '' => '2dsphere'] ); // end-geo // start-unique -$result = $collection->createIndex(['' => 1], ['unique' => true]); +$indexName = $collection->createIndex(['' => 1], ['unique' => true]); // end-unique // start-wildcard -$result = $collection->createIndex(['$**' => 1]); +$indexName = $collection->createIndex(['$**' => 1]); // end-wildcard // start-clustered @@ -76,10 +92,10 @@ // start-list foreach ($collection->listIndexes() as $indexInfo) { - var_dump($indexInfo); + echo toJSON($indexInfo) . PHP_EOL; } // end-list // start-remove -$result = $collection->dropIndex(''); +$collection->dropIndex(''); // end-remove \ No newline at end of file diff --git a/source/indexes.txt b/source/indexes.txt index b1c3155d..cd9fa904 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -53,6 +53,16 @@ target namespace. :linenos: :emphasize-lines: 10-12 +Some examples use the ``toJSON()`` function to represent change events, which are BSON +documents, as Extended JSON. To use this function, paste the following code into your +application file: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :language: php + :dedent: + :start-after: start-to-json + :end-before: end-to-json + Single Field Index ------------------ @@ -112,6 +122,9 @@ that has GeoJSON object values: :copyable: :dedent: +To learn more about the GeoJSON data type, see :manual:`GeoJSON Objects +` in the {+mdb-server+} manual. + .. TODO: To learn more about geospatial indexes, see the :ref:`php-geospatial-index` .. guide. @@ -164,12 +177,62 @@ ascending clustered index on the ``_id`` field: .. TODO: To learn more about clustered indexes, see the :ref:`php-clustered-index` .. guide. +Text Index +---------- + +The following example creates a text index on the specified string field: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-text + :end-before: end-text + :language: php + :copyable: + :dedent: + +.. TODO: To learn more about text indexes, see the :ref:`php-text-index` +.. guide. + +List Indexes +------------ + +The following example prints a list of indexes in the +specified collection: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-list + :end-before: end-list + :language: php + :copyable: + :dedent: + +Delete an Index +--------------- + +The following example deletes an index with the specified name: + +.. literalinclude:: /includes/usage-examples/index-code-examples.php + :start-after: start-remove + :end-before: end-remove + :language: php + :copyable: + :dedent: + +.. TODO: To learn more about removing indexes, see :ref:`php-indexes-remove` +.. in the Work with Indexes guide. + Atlas Search Index Management ----------------------------- The following sections contain code examples that describe how to manage :atlas:`Atlas Search indexes `. +.. note:: Search Index Management is Asynchronous + + The {+php-library+} manages Atlas Search indexes asynchronously. The + library methods described in the following sections return the server + response immediately, but the changes to your Search indexes take + place in the background and might not complete until some time later. + .. To learn more about Atlas Search indexes, see the :ref:`php-atlas-search-index` .. guide. @@ -233,47 +296,4 @@ The following example deletes an Atlas Search index with the specified name: :dedent: .. To learn more about deleting search indexes, see the :ref:`php-atlas-search-index-drop` -.. guide. - -Text Index ----------- - -The following example creates a text index on the specified string field: - -.. literalinclude:: /includes/usage-examples/index-code-examples.php - :start-after: start-text - :end-before: end-text - :language: php - :copyable: - :dedent: - -.. TODO: To learn more about text indexes, see the :ref:`php-text-index` -.. guide. - -List Indexes ------------- - -The following example prints a list of indexes in the -specified collection: - -.. literalinclude:: /includes/usage-examples/index-code-examples.php - :start-after: start-list - :end-before: end-list - :language: php - :copyable: - :dedent: - -Delete an Index ---------------- - -The following example deletes an index with the specified name: - -.. literalinclude:: /includes/usage-examples/index-code-examples.php - :start-after: start-remove - :end-before: end-remove - :language: php - :copyable: - :dedent: - -.. TODO: To learn more about removing indexes, see :ref:`php-indexes-remove` -.. in the Work with Indexes guide. \ No newline at end of file +.. guide. \ No newline at end of file From a8de178842b5685e4094c382b2408c954d067723 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 10 Sep 2024 11:10:30 -0400 Subject: [PATCH 039/149] wip --- source/includes/usage-examples/index-code-examples.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/includes/usage-examples/index-code-examples.php b/source/includes/usage-examples/index-code-examples.php index 0bea50b0..29ec1ca3 100644 --- a/source/includes/usage-examples/index-code-examples.php +++ b/source/includes/usage-examples/index-code-examples.php @@ -32,7 +32,7 @@ function toJSON(object $document): string // start-search-create $indexName = $collection->createSearchIndex( ['mappings' => ['dynamic' => true]], - ['name' => ''] + ['name' => ''] ); // end-search-create @@ -44,7 +44,7 @@ function toJSON(object $document): string // start-search-update $collection->updateSearchIndex( - ['name' => ''], + '', ['mappings' => [ 'dynamic' => false, 'fields' => [ From 69668bd8379fb8258c52525ef97e51c129c5c55c Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 10 Sep 2024 11:16:25 -0400 Subject: [PATCH 040/149] wip --- source/includes/usage-examples/index-code-examples.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/includes/usage-examples/index-code-examples.php b/source/includes/usage-examples/index-code-examples.php index 29ec1ca3..eadedb1e 100644 --- a/source/includes/usage-examples/index-code-examples.php +++ b/source/includes/usage-examples/index-code-examples.php @@ -92,7 +92,7 @@ function toJSON(object $document): string // start-list foreach ($collection->listIndexes() as $indexInfo) { - echo toJSON($indexInfo) . PHP_EOL; + echo $indexInfo; } // end-list From 280b0f7c5aa2603e00b3dd8f622880791540a41e Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Tue, 10 Sep 2024 11:36:08 -0400 Subject: [PATCH 041/149] DOCSP-41969: Replace documents (#125) * DOCSP-41969: Replace documents * edits * wording * SA * JT feedback --- source/includes/write/replace.php | 42 ++++++ source/write.txt | 3 +- source/write/replace.txt | 210 ++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 source/includes/write/replace.php create mode 100644 source/write/replace.txt diff --git a/source/includes/write/replace.php b/source/includes/write/replace.php new file mode 100644 index 00000000..05a787c3 --- /dev/null +++ b/source/includes/write/replace.php @@ -0,0 +1,42 @@ +sample_restaurants->restaurants; +// end-db-coll + +// start-replace-one +$replace_document = [ + 'name' => 'Mongo\'s Pizza', + 'cuisine' => 'Pizza', + 'address' => [ + 'street' => '123 Pizza St', + 'zipCode' => '10003', + ], + 'borough' => 'Manhattan' +]; + +$result = $collection->replaceOne(['name' => 'Pizza Town'], $replace_document); +echo 'Modified documents: ' . $result->getModifiedCount(); +// end-replace-one + +// start-replace-options +$replace_document = [ + 'name' => 'Food World', + 'cuisine' => 'Mixed', + 'address' => [ + 'street' => '123 Food St', + 'zipCode' => '10003', + ], + 'borough' => 'Manhattan' +]; + +$result = $collection->replaceOne( + ['name' => 'Food Town'], + $replace_document, + ['upsert' => true] +); +// end-replace-options diff --git a/source/write.txt b/source/write.txt index 9352ca49..01df4cb8 100644 --- a/source/write.txt +++ b/source/write.txt @@ -7,6 +7,7 @@ Write Data to MongoDB .. toctree:: :titlesonly: :maxdepth: 1 - + + /write/replace /write/insert /write/update diff --git a/source/write/replace.txt b/source/write/replace.txt new file mode 100644 index 00000000..8e7909d6 --- /dev/null +++ b/source/write/replace.txt @@ -0,0 +1,210 @@ +.. _php-write-replace: + +================= +Replace Documents +================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: modify, change, code example + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to run a replace +operation on a MongoDB collection. A replace operation performs differently +than an update operation. An update operation modifies only the specified +fields in a target document. A replace operation removes *all* fields +in the target document and replaces them with new ones. + +To replace a document, use the ``MongoDB\Collection::replaceOne()`` method. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``$collection`` variable: + +.. literalinclude:: /includes/read/project.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +Replace Operation +----------------- + +You can perform a replace operation by using ``MongoDB\Collection::replaceOne()``. +This method removes all fields except the ``_id`` field from the first document that +matches the search criteria. It then inserts the fields and values you specify into the +document. + +Required Parameters +~~~~~~~~~~~~~~~~~~~ + +The ``replaceOne()`` method requires the following parameters: + +- **Query filter** document, which determines the documents to replace. For + more information about query filters, see the + :manual:`Query Filter Documents section ` in + the {+mdb-server+} manual. +- **Replace** document, which specifies the fields and values to insert in the new + document. + +Return Value +~~~~~~~~~~~~ + +The ``replaceOne()`` method returns a ``MongoDB\UpdateResult`` +object. The ``MongoDB\UpdateResult`` type contains the following +methods: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Method + - Description + + * - ``getMatchedCount()`` + - | Returns the number of documents that matched the query filter, regardless of + how many were updated. + + * - ``getModifiedCount()`` + - | Returns the number of documents modified by the update operation. If an updated + document is identical to the original, it is not included in this + count. + + * - ``getUpsertedCount()`` + - | Returns the number of documents upserted into the database, if any. + + * - ``getUpsertedId()`` + - | Returns the ID of the document that was upserted in the database, if the driver + performed an upsert. + + * - ``isAcknowledged()`` + - | Returns a boolean indicating whether the write operation was acknowledged. + +Example +~~~~~~~ + +The following example uses the ``replaceOne()`` method to replace the fields and values +of a document in which the ``name`` field value is ``'Pizza Town'``. It then prints +the number of modified documents: + +.. io-code-block:: + :copyable: + + .. input:: /includes/write/replace.php + :start-after: start-replace-one + :end-before: end-replace-one + :language: php + :dedent: + + .. output:: + :visible: false + + Modified documents: 1 + +.. important:: + + The values of ``_id`` fields are immutable. If your replacement document specifies + a value for the ``_id`` field, it must match the ``_id`` value of the existing document. + +Modify the Replace Operation +---------------------------- + +You can modify the behavior of the ``MongoDB\Collection::replaceOne()`` method +by passing an array that specifies option values as a parameter. The following +table describes some options you can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``upsert`` + - | Specifies whether the replace operation performs an upsert operation if no + documents match the query filter. For more information, see the :manual:`upsert + statement ` + in the {+mdb-server+} manual. + | Defaults to ``false``. + + * - ``bypassDocumentValidation`` + - | Specifies whether the replace operation bypasses document validation. This lets you + replace documents that don't meet the schema validation requirements, if any + exist. For more information about schema validation, see :manual:`Schema + Validation ` in the MongoDB + Server manual. + | Defaults to ``false``. + + * - ``collation`` + - | Specifies the kind of language collation to use when sorting + results. For more information, see :manual:`Collation ` + in the {+mdb-server+} manual. + + * - ``hint`` + - | Gets or sets the index to scan for documents. + For more information, see the :manual:`hint statement ` + in the {+mdb-server+} manual. + + * - ``session`` + - | Specifies the client session to associate with the operation. + + * - ``let`` + - | Specifies a document with a list of values to improve operation readability. + Values must be constant or closed expressions that don't reference document + fields. For more information, see the :manual:`let statement + ` in the + {+mdb-server+} manual. + + * - ``comment`` + - | Attaches a comment to the operation. For more information, see the :manual:`insert command + fields ` guide in the + {+mdb-server+} manual. + +Example +~~~~~~~ + +The following code uses the ``replaceOne()`` method to find the first document +in which the ``name`` field has the value ``'Food Town'``, then replaces this document +with a new document in which the ``name`` value is ``'Food World'``. Because the +``upsert`` option is set to ``true``, the library inserts a new document if the query +filter doesn't match any existing documents: + +.. literalinclude:: /includes/write/replace.php + :start-after: start-replace-options + :end-before: end-replace-options + :language: php + :copyable: + +Additional Information +---------------------- + +To learn more about update operations, see the :ref:`php-write-update` guide. + +To learn more about creating query filters, see the :ref:`php-specify-query` guide. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::replaceOne() <{+api+}/method/MongoDBCollection-replaceOne/>`__ +- `MongoDB\\UpdateResult <{+api+}/class/MongoDBUpdateResult/>`__ From cbc3879eea4e26edee721a11206d2c3f7ce6d151 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 10 Sep 2024 12:39:40 -0400 Subject: [PATCH 042/149] JM tech review 2 --- source/includes/usage-examples/index-code-examples.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/includes/usage-examples/index-code-examples.php b/source/includes/usage-examples/index-code-examples.php index eadedb1e..4dee0dc4 100644 --- a/source/includes/usage-examples/index-code-examples.php +++ b/source/includes/usage-examples/index-code-examples.php @@ -38,7 +38,7 @@ function toJSON(object $document): string // start-search-list foreach ($collection->listSearchIndexes() as $indexInfo) { - echo toJSON($indexInfo) . PHP_EOL; + echo toJSON($indexInfo) , PHP_EOL; } // end-search-list From 3362eb19603bbc6ca24b32c1a11ad8a88f380286 Mon Sep 17 00:00:00 2001 From: Brandon Ly Date: Tue, 10 Sep 2024 12:14:32 -0500 Subject: [PATCH 043/149] Add files via upload --- build.sh | 8 ++++++++ netlify.toml | 9 +++++++++ 2 files changed, 17 insertions(+) create mode 100644 build.sh create mode 100644 netlify.toml diff --git a/build.sh b/build.sh new file mode 100644 index 00000000..b62b6772 --- /dev/null +++ b/build.sh @@ -0,0 +1,8 @@ +# ensures that we always use the latest version of the script +if [ -f build-site.sh ]; then + rm build-site.sh +fi + + +curl https://raw.githubusercontent.com/mongodb/docs-worker-pool/netlify-poc/scripts/build-site.sh -o build-site.sh +sh build-site.sh \ No newline at end of file diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 00000000..2d0a3b98 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,9 @@ +[[integrations]] +name = "snooty-cache-plugin" + +# Production context: all deploys from the Production branch +# set in your site’s Branches settings in the UI will inherit +# these settings. +[build] +publish = "snooty/public" +command = ". ./build.sh" From b9825a19f7dd3c2459c9828a349b9a0bbffc6814 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Tue, 10 Sep 2024 13:28:11 -0400 Subject: [PATCH 044/149] DOCSP-41970: Delete documents (#128) Adds a guide that shows how to delete documents. --- source/includes/write/delete.php | 34 ++++++ source/write.txt | 1 + source/write/delete.txt | 199 +++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 source/includes/write/delete.php create mode 100644 source/write/delete.txt diff --git a/source/includes/write/delete.php b/source/includes/write/delete.php new file mode 100644 index 00000000..50a5f910 --- /dev/null +++ b/source/includes/write/delete.php @@ -0,0 +1,34 @@ +sample_restaurants->restaurants; +// end-db-coll + +// Deletes a document that has a "name" value of "Ready Penny Inn" +// start-delete-one +$collection->deleteOne(['name' => 'Ready Penny Inn']); +// end-delete-one + +// Deletes documents that have a "borough" value of "Brooklyn" +// start-delete-many +$collection->deleteMany(['borough' => 'Brooklyn']); +// end-delete-many + +// Deletes matching documents and attaches a comment to the operation +// start-delete-options +$collection->deleteMany( + ['name' => new MongoDB\BSON\Regex('Mongo')], + ['comment' => 'Deleting Mongo restaurants'], +); +// end-delete-options + +// Deletes and prints the number of documents that have a "cuisine" value of "Greek" +// start-delete-count +$result = $collection->deleteMany(['cuisine' => 'Greek']); +echo 'Deleted documents: ' , $result->getDeletedCount() , PHP_EOL; +// end-delete-count + diff --git a/source/write.txt b/source/write.txt index 01df4cb8..6d95c80a 100644 --- a/source/write.txt +++ b/source/write.txt @@ -8,6 +8,7 @@ Write Data to MongoDB :titlesonly: :maxdepth: 1 + /write/delete /write/replace /write/insert /write/update diff --git a/source/write/delete.txt b/source/write/delete.txt new file mode 100644 index 00000000..c45f16dd --- /dev/null +++ b/source/write/delete.txt @@ -0,0 +1,199 @@ +.. _php-write-delete: + +================ +Delete Documents +================ + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: remove, drop, code example + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to remove +documents from a MongoDB collection by performing **delete operations**. + +A delete operation removes one or more documents from a MongoDB collection. +You can perform a delete operation by using the ``MongoDB\Collection::deleteOne()`` +or ``MongoDB\Collection::deleteMany()`` methods. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``$collection`` variable: + +.. literalinclude:: /includes/write/delete.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +Delete Operations +----------------- + +You can perform delete operations by using the following methods: + +- ``MongoDB\Collection::deleteOne()``, which deletes *the first document* + that matches the search criteria +- ``MongoDB\Collection::deleteMany()``, which deletes *all documents* that + match the search criteria + +Each delete method requires a **query filter** document, which specifies the +search criteria to determine which documents to select for removal. +For more information about query filters, see the +:manual:`Query Filter Documents section ` in +the {+mdb-server+} manual. + +Delete One Document +~~~~~~~~~~~~~~~~~~~ + +The following example uses the ``deleteOne()`` method to remove a document in +the ``restaurants`` collection that has a ``name`` value of ``'Ready Penny Inn'``: + +.. literalinclude:: /includes/write/delete.php + :start-after: start-delete-one + :end-before: end-delete-one + :language: php + :dedent: + +Delete Multiple Documents +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example uses the ``deleteMany()`` method to remove all documents +in the ``restaurants`` collection that have a ``borough`` value of ``'Brooklyn'``: + +.. literalinclude:: /includes/write/delete.php + :start-after: start-delete-many + :end-before: end-delete-many + :language: php + :dedent: + +Modify the Delete Operation +--------------------------- + +You can modify the behavior of the ``MongoDB\Collection::deleteOne()`` and +``MongoDB\Collection::deleteMany()`` methods by passing an array that +specifies option values as a parameter. The following table describes the +options you can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``collation`` + - | Specifies the kind of language collation to use when comparing + strings. For more information, see :manual:`Collation ` + in the {+mdb-server+} manual. + + * - ``writeConcern`` + - | Sets the write concern for the operation. This option defaults to + the collection's write concern. + For more information, see :manual:`Write Concern ` + in the {+mdb-server+} manual. + + * - ``hint`` + - | Gets or sets the index to scan for documents. + For more information, see the :manual:`hint statement ` + in the {+mdb-server+} manual. + + * - ``let`` + - | Specifies a document with a list of values to improve operation readability. + Values must be constant or closed expressions that don't reference document + fields. For more information, see the :manual:`let statement + ` in the + {+mdb-server+} manual. + + * - ``session`` + - | Specifies the client session to associate with the operation. For more + information, see :manual:`Session ` in the + {+mdb-server+} manual. + + * - ``comment`` + - | Attaches a comment to the operation. For more information, see the :manual:`delete command + fields ` guide in the + {+mdb-server+} manual. + +Example +~~~~~~~ + +The following example calls the ``deleteMany()`` method to delete all documents in +the ``restaurants`` collection that have a ``name`` value containing the string ``'Mongo'``. +It also sets the ``comment`` option in an array parameter to add a comment to the +operation: + +.. literalinclude:: /includes/write/delete.php + :start-after: start-delete-options + :end-before: end-delete-options + :language: php + :dedent: + +.. note:: + + If you replace the ``deleteMany()`` method with ``deleteOne()`` in + the preceding example, the library deletes only the first document that has + a ``name`` value containing ``'Mongo'``. + +Return Value +------------ + +The ``MongoDB\Collection::deleteOne()`` and ``MongoDB\Collection::deleteMany()`` +methods return a ``MongoDB\DeleteResult`` object. This class contains the +following member functions: + +- ``isAcknowledged()``, which returns a boolean indicating whether the operation + was acknowledged. +- ``getDeletedCount()``, which returns the number of documents deleted. If the write + operation was not acknowledged, this method throws an error. + +If the query filter does not match any documents, the driver doesn't delete any +documents and ``getDeletedCount()`` returns ``0``. + +Example +~~~~~~~ + +The following example calls the ``deleteMany()`` method to delete documents +that have a ``cuisine`` value of ``'Greek'``. It then calls the ``getDeletedCount()`` +member function to print the number of deleted documents: + +.. io-code-block:: + :copyable: + + .. input:: /includes/write/delete.php + :start-after: start-delete-count + :end-before: end-delete-count + :language: php + :dedent: + + .. output:: + :visible: false + + Deleted documents: 111 + +API Documentation +----------------- + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::deleteOne() <{+api+}/method/MongoDBCollection-deleteOne/>`__ +- `MongoDB\\Collection::deleteMany() <{+api+}/method/MongoDBCollection-deleteMany/>`__ +- `MongoDB\\DeleteResult <{+api+}/class/MongoDBDeleteResult/>`__ From 7a1a92995c24ab33cc10b772d37e47c534842ef4 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 10 Sep 2024 16:36:40 -0400 Subject: [PATCH 045/149] DOCSP-41984: single field index --- source/includes/indexes/indexes.php | 33 ++++++ source/indexes.txt | 11 +- source/indexes/index-mgmt.txt | 139 ++++++++++++++++++++++++++ source/indexes/single-field-index.txt | 95 ++++++++++++++++++ 4 files changed, 273 insertions(+), 5 deletions(-) create mode 100644 source/includes/indexes/indexes.php create mode 100644 source/indexes/index-mgmt.txt create mode 100644 source/indexes/single-field-index.txt diff --git a/source/includes/indexes/indexes.php b/source/includes/indexes/indexes.php new file mode 100644 index 00000000..5b51eaeb --- /dev/null +++ b/source/includes/indexes/indexes.php @@ -0,0 +1,33 @@ +sample_mflix; +$collection = $database->movies; + +// start-list-indexes +foreach ($collection->listIndexes() as $indexInfo) { + echo $indexInfo; +} +// end-list-indexes + +// start-remove-index +$collection->dropIndex('_title_'); +// end-remove-index + +// start-remove-all-indexes +$collection->dropIndexes(); +// end-remove-all-indexes + +// start-index-single +$indexName = $collection->createIndex(['title' => 1]); +// end-index-single + +// start-index-single-query +$document = $collection->findOne(['title' => 'Sweethearts']); +echo json_encode($document) , "\n"; +// end-index-single-query + diff --git a/source/indexes.txt b/source/indexes.txt index cd9fa904..daa9e985 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -18,11 +18,12 @@ Optimize Queries by Using Indexes :description: Learn how to use indexes by using the MongoDB PHP Library. :keywords: query, optimization, efficiency, usage example, code example -.. .. toctree:: -.. :titlesonly: -.. :maxdepth: 1 -.. -.. /work-with-indexes +.. toctree:: + :titlesonly: + :maxdepth: 1 + + /indexes/index-mgmt + /indexes/single-field-index Overview -------- diff --git a/source/indexes/index-mgmt.txt b/source/indexes/index-mgmt.txt new file mode 100644 index 00000000..57f2c165 --- /dev/null +++ b/source/indexes/index-mgmt.txt @@ -0,0 +1,139 @@ +.. _php-index-mgmt: + +=================================== +Index Considerations and Management +=================================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: query, optimization, efficiency + +Overview +-------- + +In this guide, you can learn about using **indexes** to improve the +efficiency of your queries and add functionality to querying and +storing documents. + +Without a relevant index, MongoDB scans every document in a collection +to find the documents that match a query. These collection scans are +slow and can negatively affect the performance of your application. +However, if the appropriate index exists, MongoDB can use the index to +reduce the number of documents to inspect. + +Operational Considerations +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To improve query performance, build indexes on fields that appear often in +your application's queries or operations that return sorted results. Each +index that you add consumes disk space and memory, so we recommend +that you track memory and disk usage when doing capacity planning. In addition, +when a write operation updates an indexed field, MongoDB updates the related +index, which can negatively impact performance for write operations. + +You can use :manual:`wildcard indexes ` in your +MongoDB application to query against fields whose names are not known in +advance or are arbitrary. Wildcard indexes are *not* designed to replace +workload-based index planning. + +To learn more about designing your data model and choosing +indexes, see the :manual:`Data Modeling and Indexes +` guide in the {+mdb-server+} +manual. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``movies`` collection in the +``sample_mflix`` 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. + +Create an Index +--------------- + +MongoDB supports several index types to help query your data. +The following pages describe different index types and provide sample +code to programmatically create each type of index. + +- :ref:`php-single-field-index` + +.. - :ref:`php-compound-index` +.. - :ref:`php-atlas-search-index` + +List Indexes +------------ + +You can retrieve a list of indexes on a collection by calling the +``MongoDB\Collection::listIndexes()`` method: + +.. literalinclude:: /includes/indexes/indexes.php + :language: php + :start-after: start-list-indexes + :end-before: end-list-indexes + :dedent: + +Remove an Index +--------------- + +You can remove any unused index except the default unique index on the +``_id`` field. + +The following sections provide examples that show how to remove one or +more indexes from a collection. + +Delete a Single Index +~~~~~~~~~~~~~~~~~~~~~ + +Pass the name of an index to the ``MongoDB\Collection::dropIndex()`` +method to remove an index from a collection. + +The following example removes the ``'_title_'`` index from the +``movies`` collection: + +.. literalinclude:: /includes/indexes/indexes.php + :language: php + :start-after: start-remove-index + :end-before: end-remove-index + :dedent: + +.. note:: + + You cannot remove a single field from a compound index. You must + drop the entire index and create a new one to update the indexed + fields. + +Delete All Indexes +~~~~~~~~~~~~~~~~~~ + +You can drop all indexes by calling the +``MongoDB\Collection::dropIndexes()`` method on a collection: + +.. literalinclude:: /includes/indexes/indexes.php + :language: php + :start-after: start-remove-all-indexes + :end-before: end-remove-all-indexes + :dedent: + +The ``dropIndexes()`` method returns information about the number of +indexes removed and a success message. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- `MongoDB\\Collection::listIndexes() <{+api+}/method/MongoDBCollection-listIndexes/>`__ +- `MongoDB\\Collection::dropIndex() <{+api+}/method/MongoDBCollection-dropIndex/>`__ +- `MongoDB\\Collection::dropIndexes() <{+api+}/method/MongoDBCollection-dropIndexes/>`__ diff --git a/source/indexes/single-field-index.txt b/source/indexes/single-field-index.txt new file mode 100644 index 00000000..8e570745 --- /dev/null +++ b/source/indexes/single-field-index.txt @@ -0,0 +1,95 @@ +.. _php-single-field-index: + +==================== +Single Field Indexes +==================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: index, query, optimization, efficiency + +Overview +-------- + +Single field indexes are indexes with a reference to a single field of a +document in a collection. These indexes improve single field query and +sort performance, and support :manual:`TTL Indexes ` +that automatically remove documents from a collection after a certain +amount of time or at a specified clock time. + +When creating a single-field index, you must specify the following +details: + +- The field on which to create the index +- The sort order for the indexed values as either ascending or + descending + +.. note:: + + The default ``_id_`` index is an example of a single-field index. + This index is automatically created on the ``_id`` field when a new + collection is created. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``movies`` collection in the +``sample_mflix`` 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. + +Create Single-Field Index +------------------------- + +The following example creates an index in ascending order on the +``title`` field: + +.. literalinclude:: /includes/indexes/indexes.php + :start-after: start-index-single + :end-before: end-index-single + :language: php + :copyable: + :dedent: + +The following is an example of a query that is covered by the index +created in the preceding code example: + +.. io-code-block:: + :copyable: true + + .. input:: /includes/indexes/indexes.php + :start-after: start-index-single-query + :end-before: end-index-single-query + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":...,"plot":"A musical comedy duo...", + "genres":["Musical"],...,"title":"Sweethearts",...} + +Additional Information +---------------------- + +To learn more about single-field indexes, see :manual:`Single Field +Indexes ` in the {+mdb-server+} manual. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods discussed in this guide, see the following API +documentation: + +- `MongoDB\\Collection::createIndex() <{+api+}/method/MongoDBCollection-createIndex/>`__ +- `MongoDB\\Collection::findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ From 4b16ca3132527680856935c216ee4b746c2dbd9d Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 10 Sep 2024 16:41:19 -0400 Subject: [PATCH 046/149] wip --- source/indexes/single-field-index.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/indexes/single-field-index.txt b/source/indexes/single-field-index.txt index 8e570745..c4c833d2 100644 --- a/source/indexes/single-field-index.txt +++ b/source/indexes/single-field-index.txt @@ -51,7 +51,8 @@ load the sample datasets, see the :atlas:`Get Started with Atlas Create Single-Field Index ------------------------- -The following example creates an index in ascending order on the +Use the ``MongoDB\Collection::createIndex()`` method to create a single +field index. The following example creates an index in ascending order on the ``title`` field: .. literalinclude:: /includes/indexes/indexes.php From 334e56597adea0255fc219c645028f5840d06e9a Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 16:09:36 -0400 Subject: [PATCH 047/149] JS PR fixes 1 --- source/indexes/index-mgmt.txt | 8 ++++---- source/indexes/single-field-index.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/indexes/index-mgmt.txt b/source/indexes/index-mgmt.txt index 57f2c165..939b4939 100644 --- a/source/indexes/index-mgmt.txt +++ b/source/indexes/index-mgmt.txt @@ -46,9 +46,9 @@ advance or are arbitrary. Wildcard indexes are *not* designed to replace workload-based index planning. To learn more about designing your data model and choosing -indexes, see the :manual:`Data Modeling and Indexes -` guide in the {+mdb-server+} -manual. +indexes, see the :manual:`Indexes +` section of the Operational +Factors and Data Models guide in the {+mdb-server+} manual. Sample Data ~~~~~~~~~~~ @@ -116,7 +116,7 @@ The following example removes the ``'_title_'`` index from the Delete All Indexes ~~~~~~~~~~~~~~~~~~ -You can drop all indexes by calling the +You can delete all indexes by calling the ``MongoDB\Collection::dropIndexes()`` method on a collection: .. literalinclude:: /includes/indexes/indexes.php diff --git a/source/indexes/single-field-index.txt b/source/indexes/single-field-index.txt index c4c833d2..cd6de01d 100644 --- a/source/indexes/single-field-index.txt +++ b/source/indexes/single-field-index.txt @@ -22,7 +22,7 @@ Overview Single field indexes are indexes with a reference to a single field of a document in a collection. These indexes improve single field query and -sort performance, and support :manual:`TTL Indexes ` +sort performance. They also support :manual:`TTL Indexes ` that automatically remove documents from a collection after a certain amount of time or at a specified clock time. From afd284a32f74d14538b3a049ac4358a148b5fedd Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 16:10:58 -0400 Subject: [PATCH 048/149] wip --- source/includes/indexes/indexes.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/includes/indexes/indexes.php b/source/includes/indexes/indexes.php index 5b51eaeb..6b037dac 100644 --- a/source/includes/indexes/indexes.php +++ b/source/includes/indexes/indexes.php @@ -28,6 +28,5 @@ // start-index-single-query $document = $collection->findOne(['title' => 'Sweethearts']); -echo json_encode($document) , "\n"; +echo json_encode($document) , PHP_EOL; // end-index-single-query - From 4fd14519f1ece0ab2a15cb15ce1ed3e6e80f412a Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 12 Sep 2024 16:49:57 -0400 Subject: [PATCH 049/149] DOCSP-41986: multikey indexes --- source/includes/indexes/indexes.php | 11 ++++ source/indexes.txt | 1 + source/indexes/index-mgmt.txt | 1 + source/indexes/multikey-index.txt | 85 +++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 source/indexes/multikey-index.txt diff --git a/source/includes/indexes/indexes.php b/source/includes/indexes/indexes.php index 6b037dac..403ad298 100644 --- a/source/includes/indexes/indexes.php +++ b/source/includes/indexes/indexes.php @@ -30,3 +30,14 @@ $document = $collection->findOne(['title' => 'Sweethearts']); echo json_encode($document) , PHP_EOL; // end-index-single-query + +// start-multikey +$indexName = $collection->createIndex(['cast' => 1]); +// end-multikey + +// start-index-array-query +$document = $collection->findOne( + ['cast' => ['$in' => ['Aamir Khan', 'Kajol']]] +); +echo json_encode($document) , PHP_EOL; +// end-index-array-query diff --git a/source/indexes.txt b/source/indexes.txt index daa9e985..634dce6d 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -24,6 +24,7 @@ Optimize Queries by Using Indexes /indexes/index-mgmt /indexes/single-field-index + /indexes/multikey-index Overview -------- diff --git a/source/indexes/index-mgmt.txt b/source/indexes/index-mgmt.txt index 939b4939..4630d4ce 100644 --- a/source/indexes/index-mgmt.txt +++ b/source/indexes/index-mgmt.txt @@ -67,6 +67,7 @@ The following pages describe different index types and provide sample code to programmatically create each type of index. - :ref:`php-single-field-index` +- :ref:`php-multikey-index` .. - :ref:`php-compound-index` .. - :ref:`php-atlas-search-index` diff --git a/source/indexes/multikey-index.txt b/source/indexes/multikey-index.txt new file mode 100644 index 00000000..2e02bde3 --- /dev/null +++ b/source/indexes/multikey-index.txt @@ -0,0 +1,85 @@ +.. _php-multikey-index: + +================ +Multikey Indexes +================ + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: index, query, optimization, efficiency + +Overview +-------- + +**Multikey indexes** are indexes that improve the performance of queries +on array-valued fields. You can create a multikey index on a collection +by using the ``MongoDB\Collection::createIndex()`` method and the same +syntax that you use to create single field or compound indexes. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``movies`` collection in the +``sample_mflix`` 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. + +Create a Multikey Index +----------------------- + +Use the ``MongoDB\Collection::createIndex()`` method to create a +multikey index. The following example creates an index in ascending +order on the array-valued ``cast`` field: + +.. literalinclude:: /includes/indexes/indexes.php + :start-after: start-multikey + :end-before: end-multikey + :language: php + :copyable: + :dedent: + +The following is an example of a query that is covered by the index +created in the preceding code example: + +.. io-code-block:: + :copyable: true + + .. input:: /includes/indexes/indexes.php + :start-after: start-index-array-query + :end-before: end-index-array-query + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":...,"title":"Holi",...,"cast":["Ashutosh Gowariker", + "Aamir Khan","Rahul Ranade","Sanjeev Gandhi"],...} + +Additional Information +---------------------- + +Multikey indexes behave differently from other indexes in terms of query +coverage, index bound computation, and sort behavior. To learn more +about the behavior and limitations of multikey indexes, see +:manual:`Multikey Indexes ` in the {+mdb-server+} +manual. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods discussed in this guide, see the following API +documentation: + +- `MongoDB\\Collection::createIndex() <{+api+}/method/MongoDBCollection-createIndex/>`__ +- `MongoDB\\Collection::findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ From 3148b8f327a54f4f8a451aa76144e8449f56647d Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 12 Sep 2024 16:56:03 -0400 Subject: [PATCH 050/149] links --- source/indexes/index-mgmt.txt | 6 +++--- source/indexes/multikey-index.txt | 4 ++-- source/indexes/single-field-index.txt | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/indexes/index-mgmt.txt b/source/indexes/index-mgmt.txt index 4630d4ce..c3bcdac7 100644 --- a/source/indexes/index-mgmt.txt +++ b/source/indexes/index-mgmt.txt @@ -135,6 +135,6 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::listIndexes() <{+api+}/method/MongoDBCollection-listIndexes/>`__ -- `MongoDB\\Collection::dropIndex() <{+api+}/method/MongoDBCollection-dropIndex/>`__ -- `MongoDB\\Collection::dropIndexes() <{+api+}/method/MongoDBCollection-dropIndexes/>`__ +:phpmethod:`MongoDB\Collection::listIndexes()` +:phpmethod:`MongoDB\Collection::dropIndex()` +:phpmethod:`MongoDB\Collection::dropIndexes()` diff --git a/source/indexes/multikey-index.txt b/source/indexes/multikey-index.txt index 2e02bde3..2ca9f507 100644 --- a/source/indexes/multikey-index.txt +++ b/source/indexes/multikey-index.txt @@ -81,5 +81,5 @@ API Documentation To learn more about any of the methods discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::createIndex() <{+api+}/method/MongoDBCollection-createIndex/>`__ -- `MongoDB\\Collection::findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ +:phpmethod:`MongoDB\Collection::createIndex()` +:phpmethod:`MongoDB\Collection::findOne()` diff --git a/source/indexes/single-field-index.txt b/source/indexes/single-field-index.txt index cd6de01d..e44dcb89 100644 --- a/source/indexes/single-field-index.txt +++ b/source/indexes/single-field-index.txt @@ -92,5 +92,5 @@ API Documentation To learn more about any of the methods discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::createIndex() <{+api+}/method/MongoDBCollection-createIndex/>`__ -- `MongoDB\\Collection::findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ +:phpmethod:`MongoDB\Collection::createIndex()` +:phpmethod:`MongoDB\Collection::findOne()` From 54374928c4ac79dd3a87583a0f0b49953f815d90 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 12 Sep 2024 16:57:01 -0400 Subject: [PATCH 051/149] bullet pts --- source/indexes/index-mgmt.txt | 6 +++--- source/indexes/multikey-index.txt | 4 ++-- source/indexes/single-field-index.txt | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/indexes/index-mgmt.txt b/source/indexes/index-mgmt.txt index c3bcdac7..92fb541a 100644 --- a/source/indexes/index-mgmt.txt +++ b/source/indexes/index-mgmt.txt @@ -135,6 +135,6 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -:phpmethod:`MongoDB\Collection::listIndexes()` -:phpmethod:`MongoDB\Collection::dropIndex()` -:phpmethod:`MongoDB\Collection::dropIndexes()` +- :phpmethod:`MongoDB\Collection::listIndexes()` +- :phpmethod:`MongoDB\Collection::dropIndex()` +- :phpmethod:`MongoDB\Collection::dropIndexes()` diff --git a/source/indexes/multikey-index.txt b/source/indexes/multikey-index.txt index 2ca9f507..2288409e 100644 --- a/source/indexes/multikey-index.txt +++ b/source/indexes/multikey-index.txt @@ -81,5 +81,5 @@ API Documentation To learn more about any of the methods discussed in this guide, see the following API documentation: -:phpmethod:`MongoDB\Collection::createIndex()` -:phpmethod:`MongoDB\Collection::findOne()` +- :phpmethod:`MongoDB\Collection::createIndex()` +- :phpmethod:`MongoDB\Collection::findOne()` diff --git a/source/indexes/single-field-index.txt b/source/indexes/single-field-index.txt index e44dcb89..aa0c0404 100644 --- a/source/indexes/single-field-index.txt +++ b/source/indexes/single-field-index.txt @@ -92,5 +92,5 @@ API Documentation To learn more about any of the methods discussed in this guide, see the following API documentation: -:phpmethod:`MongoDB\Collection::createIndex()` -:phpmethod:`MongoDB\Collection::findOne()` +- :phpmethod:`MongoDB\Collection::createIndex()` +- :phpmethod:`MongoDB\Collection::findOne()` From 343513524d35a7753a4c12c7ebf69a058a4d4d93 Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 13 Sep 2024 14:54:00 -0400 Subject: [PATCH 052/149] JS suggestion --- source/indexes/multikey-index.txt | 6 +++++- source/indexes/single-field-index.txt | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/source/indexes/multikey-index.txt b/source/indexes/multikey-index.txt index 2288409e..b3ef21d9 100644 --- a/source/indexes/multikey-index.txt +++ b/source/indexes/multikey-index.txt @@ -23,7 +23,8 @@ Overview **Multikey indexes** are indexes that improve the performance of queries on array-valued fields. You can create a multikey index on a collection by using the ``MongoDB\Collection::createIndex()`` method and the same -syntax that you use to create single field or compound indexes. +syntax that you use to create :ref:`single field +` or compound indexes. Sample Data ~~~~~~~~~~~ @@ -75,6 +76,9 @@ about the behavior and limitations of multikey indexes, see :manual:`Multikey Indexes ` in the {+mdb-server+} manual. +To view runnable examples that demonstrate how to manage indexes, see +:ref:`php-indexes`. + API Documentation ~~~~~~~~~~~~~~~~~ diff --git a/source/indexes/single-field-index.txt b/source/indexes/single-field-index.txt index aa0c0404..d5eac3d7 100644 --- a/source/indexes/single-field-index.txt +++ b/source/indexes/single-field-index.txt @@ -83,6 +83,9 @@ created in the preceding code example: Additional Information ---------------------- +To view runnable examples that demonstrate how to manage indexes, see +:ref:`php-indexes`. + To learn more about single-field indexes, see :manual:`Single Field Indexes ` in the {+mdb-server+} manual. From 6e5971107a05980c770bbec0dcf7c57b62968848 Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 13 Sep 2024 16:24:44 -0400 Subject: [PATCH 053/149] fix whitespace per JM comment --- source/includes/indexes/indexes.php | 4 ++-- source/includes/usage-examples/index-code-examples.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/includes/indexes/indexes.php b/source/includes/indexes/indexes.php index 403ad298..ae865cdb 100644 --- a/source/includes/indexes/indexes.php +++ b/source/includes/indexes/indexes.php @@ -28,7 +28,7 @@ // start-index-single-query $document = $collection->findOne(['title' => 'Sweethearts']); -echo json_encode($document) , PHP_EOL; +echo json_encode($document), PHP_EOL; // end-index-single-query // start-multikey @@ -39,5 +39,5 @@ $document = $collection->findOne( ['cast' => ['$in' => ['Aamir Khan', 'Kajol']]] ); -echo json_encode($document) , PHP_EOL; +echo json_encode($document), PHP_EOL; // end-index-array-query diff --git a/source/includes/usage-examples/index-code-examples.php b/source/includes/usage-examples/index-code-examples.php index 4dee0dc4..779e3a4e 100644 --- a/source/includes/usage-examples/index-code-examples.php +++ b/source/includes/usage-examples/index-code-examples.php @@ -38,7 +38,7 @@ function toJSON(object $document): string // start-search-list foreach ($collection->listSearchIndexes() as $indexInfo) { - echo toJSON($indexInfo) , PHP_EOL; + echo toJSON($indexInfo), PHP_EOL; } // end-search-list From 60f5c9cfda29a67d57cca6c4d1ae6811ba9c7d1b Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 13 Sep 2024 16:25:15 -0400 Subject: [PATCH 054/149] uncomment --- source/indexes.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/indexes.txt b/source/indexes.txt index 634dce6d..2523bfb7 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -108,8 +108,8 @@ specified array-valued field: :copyable: :dedent: -.. TODO To learn more about multikey indexes, see the :ref:`php-multikey-index` -.. guide. +To learn more about multikey indexes, see the :ref:`php-multikey-index` +guide. Geospatial Index ---------------- From d762275e40309b56ed82dc2532ef2156a8c23b55 Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 13 Sep 2024 16:03:11 -0400 Subject: [PATCH 055/149] DOCSP-41985: compound idx --- source/includes/indexes/indexes.php | 14 +++++ source/indexes.txt | 20 ++++--- source/indexes/compound-index.txt | 86 +++++++++++++++++++++++++++ source/indexes/index-mgmt.txt | 2 +- source/indexes/single-field-index.txt | 2 +- 5 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 source/indexes/compound-index.txt diff --git a/source/includes/indexes/indexes.php b/source/includes/indexes/indexes.php index ae865cdb..e8cc9382 100644 --- a/source/includes/indexes/indexes.php +++ b/source/includes/indexes/indexes.php @@ -31,6 +31,20 @@ echo json_encode($document), PHP_EOL; // end-index-single-query +// start-index-compound +$indexName = $collection->createIndex( + ['title' => 1, 'year' => 1] +); +// end-index-compound + +// start-compound-query +$document = $collection->findOne( + ['title' => ['$regex' => 'Sunrise'], + 'year' => ['$gte' => 1990]] +); +echo json_encode($document) , PHP_EOL; +// end-compound-query + // start-multikey $indexName = $collection->createIndex(['cast' => 1]); // end-multikey diff --git a/source/indexes.txt b/source/indexes.txt index 2523bfb7..3aa04f52 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -24,6 +24,7 @@ Optimize Queries by Using Indexes /indexes/index-mgmt /indexes/single-field-index + /indexes/compound-index /indexes/multikey-index Overview @@ -32,11 +33,11 @@ Overview On this page, you can see copyable code examples that show how to manage different types of indexes by using the {+php-library+}. -.. .. tip:: -.. -.. To learn more about working with indexes, see the :ref:`php-work-indexes` -.. guide. To learn more about any of the indexes shown on this page, see the link -.. provided in each section. +.. tip:: + + To learn more about working with indexes, see the :ref:`php-index-mgmt` + guide. To learn more about any of the indexes shown on this page, see the link + provided in each section. To use an example from this page, copy the code example into the :ref:`sample application ` or your own application. @@ -77,8 +78,8 @@ The following example creates an ascending index on the specified field: :copyable: :dedent: -.. To learn more about single field indexes, see the -.. :ref:`php-single-field-index` guide. +To learn more about single field indexes, see the +:ref:`php-single-field-index` guide. Compound Index -------------- @@ -93,7 +94,8 @@ on the specified fields: :copyable: :dedent: -.. To learn more about compound indexes, see the :ref:`php-compound-index` guide. +To learn more about compound indexes, see the :ref:`php-compound-index` +guide. Multikey Index -------------- @@ -298,4 +300,4 @@ The following example deletes an Atlas Search index with the specified name: :dedent: .. To learn more about deleting search indexes, see the :ref:`php-atlas-search-index-drop` -.. guide. \ No newline at end of file +.. guide. diff --git a/source/indexes/compound-index.txt b/source/indexes/compound-index.txt new file mode 100644 index 00000000..15d4960e --- /dev/null +++ b/source/indexes/compound-index.txt @@ -0,0 +1,86 @@ +.. _php-compound-index: + +================ +Compound Indexes +================ + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: index, query, optimization, efficiency + +Overview +-------- + +**Compound indexes** hold references to multiple +fields within a collection's documents, improving query and sort +performance. You can create a multikey index on a collection +by using the ``MongoDB\Collection::createIndex()`` method and the same +syntax that you use to create :ref:`single field indexes +`. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``movies`` collection in the +``sample_mflix`` 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. + +Create a Compound Index +----------------------- + +Use the ``MongoDB\Collection::createIndex()`` method to create a +compound index. The following example creates an index in ascending +order on the ``title`` and ``year`` fields: + +.. literalinclude:: /includes/indexes/indexes.php + :start-after: start-index-compound + :end-before: end-index-compound + :language: php + :copyable: + :dedent: + +The following is an example of a query that is covered by the index +created in the preceding code example: + +.. io-code-block:: + :copyable: true + + .. input:: /includes/indexes/indexes.php + :start-after: start-compound-query + :end-before: end-compound-query + :language: php + :dedent: + + .. output:: + :visible: false + + {"_id":...,"title":"Before Sunrise",...,"year":1995,...} + +Additional Information +---------------------- + +To learn more about compound indexes, see :manual:`Compound +Indexes ` in the {+mdb-server+} manual. + +To view runnable examples that demonstrate how to manage indexes, see +:ref:`php-indexes`. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods discussed in this guide, see the following API +documentation: + +- :phpmethod:`MongoDB\Collection::createIndex()` +- :phpmethod:`MongoDB\Collection::findOne()` diff --git a/source/indexes/index-mgmt.txt b/source/indexes/index-mgmt.txt index 92fb541a..adf19d9b 100644 --- a/source/indexes/index-mgmt.txt +++ b/source/indexes/index-mgmt.txt @@ -67,9 +67,9 @@ The following pages describe different index types and provide sample code to programmatically create each type of index. - :ref:`php-single-field-index` +- :ref:`php-compound-index` - :ref:`php-multikey-index` -.. - :ref:`php-compound-index` .. - :ref:`php-atlas-search-index` List Indexes diff --git a/source/indexes/single-field-index.txt b/source/indexes/single-field-index.txt index d5eac3d7..df137fb2 100644 --- a/source/indexes/single-field-index.txt +++ b/source/indexes/single-field-index.txt @@ -86,7 +86,7 @@ Additional Information To view runnable examples that demonstrate how to manage indexes, see :ref:`php-indexes`. -To learn more about single-field indexes, see :manual:`Single Field +To learn more about single field indexes, see :manual:`Single Field Indexes ` in the {+mdb-server+} manual. API Documentation From a4975392469980375d03419262a44d5097baf865 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 16 Sep 2024 09:54:30 -0400 Subject: [PATCH 056/149] small fix --- source/indexes/compound-index.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/indexes/compound-index.txt b/source/indexes/compound-index.txt index 15d4960e..130eb8a2 100644 --- a/source/indexes/compound-index.txt +++ b/source/indexes/compound-index.txt @@ -22,7 +22,7 @@ Overview **Compound indexes** hold references to multiple fields within a collection's documents, improving query and sort -performance. You can create a multikey index on a collection +performance. You can create a compound index on a collection by using the ``MongoDB\Collection::createIndex()`` method and the same syntax that you use to create :ref:`single field indexes `. From 4e1994b0cb5f3f0c3cafb7df5a9e331b519de218 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 16 Sep 2024 12:18:07 -0400 Subject: [PATCH 057/149] DOCSP-41966: Write operations landing (#135) * DOCSP-41966: Write operations landing * edits * RR feedback * JT feedback * JT feedback 2 * gridfs examples --- snooty.toml | 1 + .../usage-examples/write-code-examples.php | 116 ++++++++++++ source/write.txt | 172 ++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 source/includes/usage-examples/write-code-examples.php diff --git a/snooty.toml b/snooty.toml index 711874cc..7f35dafe 100644 --- a/snooty.toml +++ b/snooty.toml @@ -18,6 +18,7 @@ toc_landing_pages = [ "/reference/class/MongoDBModelDatabaseInfo", "/reference/class/MongoDBModelIndexInfo", "/get-started", + "/write", ] [substitutions] diff --git a/source/includes/usage-examples/write-code-examples.php b/source/includes/usage-examples/write-code-examples.php new file mode 100644 index 00000000..8e508822 --- /dev/null +++ b/source/includes/usage-examples/write-code-examples.php @@ -0,0 +1,116 @@ +db->coll; + +// Inserts one document that stores the specified values +// start-insert-one +$result = $collection->insertOne([ + '' => '', + '' => '', +]); +// end-insert-one + +// Inserts multiple documents that store the specified values +// start-insert-multiple +$result = $collection->insertMany( + [ + '' => '', + '' => '', + ], + [ + '' => '', + '' => '', + ], +); +// end-insert-multiple + +// Updates a document that matches the specified criteria +// start-update-one +$result = $collection->updateOne( + ['' => ''], + ['$set' => ['' => '']], +); +// end-update-one + +// Updates all documents that match the specified criteria +// start-update-multiple +$result = $collection->updateMany( + ['' => ''], + ['$set' => ['' => '']], +); +// end-update-multiple + +// start-replace-one +$result = $collection->replaceOne( + ['' => ''], + [ + '' => '', + '' => '', + ], +); +// end-replace-one + +// Deletes a document that matches the specified criteria +// start-delete-one +$result = $collection->deleteOne(['' => '']); +// end-delete-one + +// Deletes all documents that match the specified criteria +// start-delete-multiple +$result = $collection->deleteMany(['' => '']); +// end-delete-multiple + +// Runs a bulk operation based on the instructions in each array entry +// start-bulk-write +$result = $collection->bulkWrite( + [ + [ + 'insertOne' => [ + ['' => ''], + ], + ], + [ + 'replaceOne' => [ + ['' => ''], + [ + '' => '', + '' => '', + ], + ], + ], + [ + 'updateOne' => [ + ['' => ''], + ['$set' => ['' => '']], + ], + ], + [ + 'updateMany' => [ + ['' => ''], + ['$set' => ['' => '']], + ], + ], + [ + 'deleteOne' => [ + ['' => ''], + ], + ], + [ + 'deleteMany' => [ + ['' => ''], + ], + ], + ] +); +// end-bulk-write + +// Stores a file in a GridFS bucket and writes data to the file +// start-gridfs-upload +$bucket = $client->selectDatabase('')->selectGridFSBucket(); +$stream = $bucket->openUploadStream(''); +fwrite($stream, ''); +fclose($stream); +// end-gridfs-upload diff --git a/source/write.txt b/source/write.txt index 6d95c80a..f2cd201e 100644 --- a/source/write.txt +++ b/source/write.txt @@ -4,6 +4,20 @@ Write Data to MongoDB ===================== +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :description: Learn how to use the PHP Library to write data to MongoDB. + :keywords: usage examples, save, crud, create, code example + .. toctree:: :titlesonly: :maxdepth: 1 @@ -12,3 +26,161 @@ Write Data to MongoDB /write/replace /write/insert /write/update + +Overview +-------- + +On this page, you can see copyable code examples that show common +{+php-library+} methods for writing data to MongoDB. + +.. tip:: + + To learn more about any of the methods shown on this page, see the link + provided in each section. + +To use an example from this page, copy the code example into the +:ref:`sample application ` or your own application. +Make sure to set the ``MONGODB_URI`` environment variable to the +connection string for your MongoDB deployment, and replace the +```` and ```` placeholders with values for your +target namespace. + +.. _php-write-sample: + +.. include:: /includes/usage-examples/sample-app-intro.rst + +.. literalinclude:: /includes/usage-examples/sample-app.php + :language: php + :dedent: + :linenos: + :emphasize-lines: 10-12 + +Insert One +---------- + +The following code shows how to insert a single document into a collection: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-insert-one + :end-before: end-insert-one + :language: php + :dedent: + +To learn more about the ``MongoDB\Collection::insertOne()`` method, see the +:ref:`Insert Documents ` guide. + +Insert Multiple +--------------- + +The following code shows how to insert multiple documents into a collection: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-insert-multiple + :end-before: end-insert-multiple + :language: php + :dedent: + +To learn more about the ``MongoDB\Collection::insertMany()`` method, see the +:ref:`Insert Documents ` guide. + +Update One +---------- + +The following code shows how to update a single document in a collection by creating +or editing a field: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-update-one + :end-before: end-update-one + :language: php + :dedent: + +To learn more about the ``MongoDB\Collection::updateOne()`` method, see the +:ref:`Update Documents ` guide. + +Update Multiple +--------------- + +The following code shows how to update multiple documents in a collection by creating +or editing a field: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-update-multiple + :end-before: end-update-multiple + :language: php + :dedent: + +To learn more about the ``MongoDB\Collection::updateMany()`` method, see the +:ref:`Update Documents ` guide. + +Replace One +----------- + +The following code shows how to replace a single document in a collection +with another document: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-replace-one + :end-before: end-replace-one + :language: php + :dedent: + +To learn more about the ``MongoDB\Collection::replaceOne()`` method, see the +:ref:`Replace Documents ` guide. + +Delete One +---------- + +The following code shows how to delete a single document in a collection: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-delete-one + :end-before: end-delete-one + :language: php + :dedent: + +To learn more about the ``MongoDB\Collection::deleteOne()`` method, see the +:ref:`Delete Documents ` guide. + +Delete Multiple +--------------- + +The following code shows how to delete multiple documents in a collection: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-delete-multiple + :end-before: end-delete-multiple + :language: php + :dedent: + +To learn more about the ``MongoDB\Collection::deleteMany()`` method, see the +:ref:`Delete Documents ` guide. + +Bulk Write +---------- + +The following code shows how to perform multiple write operations in a single bulk +operation: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-bulk-write + :end-before: end-bulk-write + :language: php + :dedent: + +To learn more about the ``MongoDB\Collection::bulkWrite()`` method, see the +:ref:`Bulk Write ` guide. + +Store Large Files +----------------- + +The following code shows how to store files in a GridFS bucket by +creating an upload stream: + +.. literalinclude:: /includes/usage-examples/write-code-examples.php + :start-after: start-gridfs-upload + :end-before: end-gridfs-upload + :language: php + :dedent: + +To learn more about GridFS, see the :ref:`Store Large Files ` guide. From 54c05bfd3fc2fd9967141dec14478fda1271cfc6 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 16 Sep 2024 14:36:10 -0400 Subject: [PATCH 058/149] DOCSP-42026: In use encryption (#142) * DOCSP-42026: In use encryption * edit --- source/index.txt | 1 + source/security.txt | 11 +++ source/security/in-use-encryption.txt | 101 ++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 source/security.txt create mode 100644 source/security/in-use-encryption.txt diff --git a/source/index.txt b/source/index.txt index b4b4841a..707a62d2 100644 --- a/source/index.txt +++ b/source/index.txt @@ -15,6 +15,7 @@ MongoDB PHP Library /write /aggregation /indexes + /security /tutorial /upgrade /reference diff --git a/source/security.txt b/source/security.txt new file mode 100644 index 00000000..2e581856 --- /dev/null +++ b/source/security.txt @@ -0,0 +1,11 @@ +.. _php-security: + +================ +Secure Your Data +================ + +.. toctree:: + :titlesonly: + :maxdepth: 1 + + /security/in-use-encryption \ No newline at end of file diff --git a/source/security/in-use-encryption.txt b/source/security/in-use-encryption.txt new file mode 100644 index 00000000..adc6e72c --- /dev/null +++ b/source/security/in-use-encryption.txt @@ -0,0 +1,101 @@ +.. _php-in-use-encryption: + +================= +In-Use Encryption +================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: qe, csfle, field level encryption + +Overview +-------- + +You can use the {+php-library+} to encrypt specific document fields by using a +set of features called **in-use encryption**. In-use encryption allows +your application to encrypt data *before* sending it to MongoDB +and query documents with encrypted fields. + +In-use encryption prevents unauthorized users from viewing plaintext +data as it is sent to MongoDB or while it is in an encrypted database. To +enable in-use encryption in an application and authorize it to decrypt +data, you must create encryption keys that only your application can +access. Only applications that have access to your encryption +keys can access the decrypted, plaintext data. If an attacker gains +access to the database, they can see only the encrypted ciphertext data +because they lack access to the encryption keys. + +You can use in-use encryption to encrypt fields in your MongoDB +documents that contain the following types of sensitive data: + +- Credit card numbers +- Addresses +- Health information +- Financial information +- Any other sensitive or personally identifiable information (PII) + +MongoDB offers the following features to enable in-use encryption: + +- :ref:`Queryable Encryption ` +- :ref:`Client-side Field Level Encryption ` + +.. _php-in-use-encryption-qe: + +Queryable Encryption +-------------------- + +Queryable Encryption is the next-generation in-use encryption feature, +first introduced as a preview feature in {+mdb-server+} version 6.0 and +as a generally available (GA) feature in MongoDB 7.0. Queryable +Encryption supports searching encrypted fields for equality and encrypts +each value uniquely. + +.. important:: Preview Feature Incompatible with MongoDB 7.0 + + The implementation of Queryable Encryption in MongoDB 6.0 is incompatible with + the GA version introduced in MongoDB 7.0. The Queryable Encryption preview + feature is no longer supported. + +To learn more about Queryable Encryption, see :manual:`Queryable +Encryption ` in the {+mdb-server+} manual. + +.. _php-in-use-encryption-csfle: + +Client-side Field Level Encryption +---------------------------------- + +Client-side Field Level Encryption (CSFLE) was introduced in {+mdb-server+} +version 4.2 and supports searching encrypted fields for equality. +CSFLE differs from Queryable Encryption in that you can select either a +deterministic or random encryption algorithm to encrypt fields. You can only +query encrypted fields that use a deterministic encryption algorithm when +using CSFLE. When you use a random encryption algorithm to encrypt +fields in CSFLE, they can be decrypted, but you cannot perform equality +queries on those fields. When you use Queryable Encryption, you cannot +specify the encryption algorithm, but you can query all encrypted +fields. + +When you deterministically encrypt a value, the same input value +produces the same output value. While deterministic encryption allows +you to perform queries on those encrypted fields, encrypted data with +low cardinality is susceptible to code breaking by frequency analysis. + +.. tip:: + + To learn more about these concepts, see the following Wikipedia + entries: + + - :wikipedia:`Cardinality ` + - :wikipedia:`Frequency Analysis ` + +To learn more about CSFLE, see :manual:`CSFLE ` in the {+mdb-server+} +manual. \ No newline at end of file From df79843225dacdaba7e9fdca68a81a2ecb333bc5 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 16 Sep 2024 15:01:28 -0400 Subject: [PATCH 059/149] DOCSP-41972: GridFS guide (#133) * DOCSP-41972: GridFS guide * fixes * code edits * fix * RR feedback * phpmethod * fix * JM most feedback * alternate upload/download methods * file revisions * code fix * tojson * edits * JM feedback 2 * edits * JM last feedback --- source/includes/figures/GridFS-upload.png | Bin 0 -> 9225 bytes source/includes/write/gridfs.php | 91 +++++ source/write.txt | 1 + source/write/gridfs.txt | 435 ++++++++++++++++++++++ 4 files changed, 527 insertions(+) create mode 100644 source/includes/figures/GridFS-upload.png create mode 100644 source/includes/write/gridfs.php create mode 100644 source/write/gridfs.txt diff --git a/source/includes/figures/GridFS-upload.png b/source/includes/figures/GridFS-upload.png new file mode 100644 index 0000000000000000000000000000000000000000..2207752bc6f9010ed0117b9d2fe7e92c97e5f3ea GIT binary patch literal 9225 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 V9DT{TC;T7J)5nHdXieMD{|6(4qLu&v literal 0 HcmV?d00001 diff --git a/source/includes/write/gridfs.php b/source/includes/write/gridfs.php new file mode 100644 index 00000000..bb94ce63 --- /dev/null +++ b/source/includes/write/gridfs.php @@ -0,0 +1,91 @@ +toRelaxedExtendedJSON(); +} +// end-to-json + +// Creates a GridFS bucket or references an existing one +// start-create-bucket +$bucket = $client->db->selectGridFSBucket(); +// end-create-bucket + +// Creates or references a GridFS bucket with a custom name +// start-create-custom-bucket +$custom_bucket = $client->db->selectGridFSBucket( + ['bucketName' => 'myCustomBucket'] +); +// end-create-custom-bucket + +// Uploads a file called "my_file" to the GridFS bucket and writes data to it +// start-open-upload-stream +$stream = $bucket->openUploadStream('my_file', [ + 'metadata' => ['contentType' => 'text/plain'] +]); +fwrite($stream, 'Data to store'); +fclose($stream); +// end-open-upload-stream + +// Uploads data to a stream, then writes the stream to a GridFS file +// start-upload-from-stream +$file = fopen('/path/to/input_file', 'rb'); +$bucket->uploadFromStream('new_file', $file); +// end-upload-from-stream + +// Prints information about each file in the bucket +// start-retrieve-file-info +$files = $bucket->find(); +foreach ($files as $file_doc) { + echo toJSON($file_doc), PHP_EOL; +} +// end-retrieve-file-info + +// Downloads the "my_file" file from the GridFS bucket and prints its contents +// start-open-download-stream-name +$stream = $bucket->openDownloadStreamByName('my_file'); +$contents = stream_get_contents($stream); +echo $contents, PHP_EOL; +fclose($stream); +// end-open-download-stream-name + +// Downloads a file from the GridFS bucket by referencing its ObjectId value +// start-download-files-id +$stream = $bucket->openDownloadStream(new ObjectId('66e0a5487c880f844c0a32b1')); +$contents = stream_get_contents($stream); +fclose($stream); +// end-download-files-id + +// Downloads the original "my_file" file from the GridFS bucket +// start-download-file-revision +$stream = $bucket->openDownloadStreamByName('my_file', ['revision' => 0]); +$contents = stream_get_contents($stream); +fclose($stream); +// end-download-file-revision + +// Downloads an entire GridFS file to a download stream +// start-download-to-stream +$file = fopen('/path/to/output_file', 'wb'); +$bucket->downloadToStream( + new ObjectId('66e0a5487c880f844c0a32b1'), + $file, +); +// end-download-to-stream + +// Renames a file from the GridFS bucket with the specified ObjectId +// start-rename-files +$bucket->rename(new ObjectId('66e0a5487c880f844c0a32b1'), 'new_file_name'); +// end-rename-files + +// Deletes a file from the GridFS bucket with the specified ObjectId +// start-delete-files +$bucket->delete(new ObjectId('66e0a5487c880f844c0a32b1')); +// end-delete-files diff --git a/source/write.txt b/source/write.txt index f2cd201e..5ce877d9 100644 --- a/source/write.txt +++ b/source/write.txt @@ -26,6 +26,7 @@ Write Data to MongoDB /write/replace /write/insert /write/update + /write/gridfs Overview -------- diff --git a/source/write/gridfs.txt b/source/write/gridfs.txt new file mode 100644 index 00000000..20bbc6dd --- /dev/null +++ b/source/write/gridfs.txt @@ -0,0 +1,435 @@ +.. _php-gridfs: + +================= +Store Large Files +================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: binary large object, blob, storage, code example + +Overview +-------- + +In this guide, you can learn how to store and retrieve large files in +MongoDB by using **GridFS**. GridFS is a specification implemented by +the {+php-library+} that describes how to split files into chunks when storing them +and reassemble them when retrieving them. The library's implementation of +GridFS is an abstraction that manages the operations and organization of +the file storage. + +Use GridFS if the size of your files exceeds the BSON document +size limit of 16MB. For more detailed information on whether GridFS is +suitable for your use case, see :manual:`GridFS ` in the +{+mdb-server+} manual. + +How GridFS Works +---------------- + +GridFS organizes files in a **bucket**, a group of MongoDB collections +that contain the chunks of files and information describing them. The +bucket contains the following collections, named using the convention +defined in the GridFS specification: + +- The ``chunks`` collection stores the binary file chunks. +- The ``files`` collection stores the file metadata. + +When you create a new GridFS bucket, the library creates the preceding +collections, prefixed with the default bucket name ``fs``, unless +you specify a different name. The library also creates an index on each +collection to ensure efficient retrieval of the files and related +metadata. The library creates the GridFS bucket, if it doesn't exist, only when the first write +operation is performed. The library creates indexes only if they don't exist and when the +bucket is empty. For more information about +GridFS indexes, see :manual:`GridFS Indexes ` +in the {+mdb-server+} manual. + +When using GridFS to store files, the library splits the files into smaller +chunks, each represented by a separate document in the ``chunks`` collection. +It also creates a document in the ``files`` collection that contains +a file ID, file name, and other file metadata. You can upload the file by passing +a stream to the {+php-library+} to consume or creating a new stream and writing to it +directly. To learn more about streams, see `Streams <{+php-manual+}/book.stream.php>`__ +in the PHP manual. + +View the following diagram to see how GridFS splits the files when uploaded to +a bucket: + +.. figure:: /includes/figures/GridFS-upload.png + :alt: A diagram that shows how GridFS uploads a file to a bucket + +When retrieving files, GridFS fetches the metadata from the ``files`` +collection in the specified bucket and uses the information to reconstruct +the file from documents in the ``chunks`` collection. You can read the file +by writing its contents to an existing stream or creating a new stream that points +to the file. + +.. _gridfs-create-bucket: + +Create a GridFS Bucket +---------------------- + +To store or retrieve files from GridFS, call the ``MongoDB\Database::selectGridFSBucket()`` +method on your database. This method accesses an existing bucket or creates +a new bucket if one does not exist. + +The following example calls the ``selectGridFSBucket()`` method on the ``db`` +database: + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-create-bucket + :end-before: end-create-bucket + +.. _gridfs-create-custom-bucket: + +Customize the Bucket +~~~~~~~~~~~~~~~~~~~~ + +You can customize the GridFS bucket configuration by passing an array that specifies +option values to the ``selectGridFSBucket()`` method. The following table describes +some options you can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``bucketName`` + - | Specifies the bucket name to use as a prefix for the files and chunks collections. + The default value is ``'fs'``. + | **Type**: ``string`` + + * - ``chunkSizeBytes`` + - | Specifies the chunk size that GridFS splits files into. The default value is ``261120``. + | **Type**: ``integer`` + + * - ``readConcern`` + - | Specifies the read concern to use for bucket operations. The default value is the + database's read concern. + | **Type**: ``MongoDB\Driver\ReadConcern`` + + * - ``readPreference`` + - | Specifies the read preference to use for bucket operations. The default value is the + database's read preference. + | **Type**: ``MongoDB\Driver\ReadPreference`` + + * - ``writeConcern`` + - | Specifies the write concern to use for bucket operations. The default value is the + database's write concern. + | **Type**: ``MongoDB\Driver\WriteConcern`` + +The following example creates a bucket named ``'myCustomBucket'`` by passing an +array to ``selectGridFSBucket()`` that sets the ``bucketName`` option: + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-create-custom-bucket + :end-before: end-create-custom-bucket + +.. _gridfs-upload-files: + +Upload Files +------------ + +You can upload files to a GridFS bucket by using the following methods: + +- ``MongoDB\GridFS\Bucket::openUploadStream()``: Opens a new upload stream + to which you can write file contents +- ``MongoDB\GridFS\Bucket::uploadFromStream()``: Uploads the contents of + an existing stream to a GridFS file + +.. _gridfs-open-upload-stream: + +Write to an Upload Stream +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the ``openUploadStream()`` method to create an upload stream for a given +file name. The ``openUploadStream()`` method allows you to specify configuration +information in an options array, which you can pass as a parameter. + +This example uses an upload stream to perform the following +actions: + +- Opens a writable stream for a new GridFS file named ``'my_file'`` +- Sets the ``metadata`` option in an array parameter + to the ``openUploadStream()`` method +- Calls the ``fwrite()`` method to write data to ``'my_file'``, which the stream points to +- Calls the ``fclose()`` method to close the stream pointing to ``'my_file'`` + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-open-upload-stream + :end-before: end-open-upload-stream + +Upload an Existing Stream +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the ``uploadFromStream()`` method to upload the contents of a stream to +a new GridFS file. The ``uploadFromStream()`` method allows you to specify configuration +information in an options array, which you can pass as a parameter. + +This example performs the following actions: + +- Calls the ``fopen()`` method to open a file located at ``/path/to/input_file`` + as a stream in binary read (``rb``) mode +- Calls the ``uploadFromStream()`` method to upload the contents of the stream + to a GridFS file named ``'new_file'`` + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-upload-from-stream + :end-before: end-upload-from-stream + +.. _gridfs-retrieve-file-info: + +Retrieve File Information +------------------------- + +In this section, you can learn how to retrieve file metadata stored in the +``files`` collection of the GridFS bucket. The metadata contains information +about the file it refers to, including: + +- The ``_id`` of the file +- The name of the file +- The length/size of the file +- The upload date and time +- A ``metadata`` document in which you can store any other information + +To retrieve files from a GridFS bucket, call the ``MongoDB\GridFS\Bucket::find()`` +method on the ``MongoDB\GridFS\Bucket`` instance. The method returns a ``MongoDB\Driver\Cursor`` +instance from which you can access the results. To learn more about ``Cursor`` objects in +the {+php-library+}, see the :ref:`` guide. + +Example +~~~~~~~ + +The following code example shows you how to retrieve and print file metadata +from files in a GridFS bucket. It uses a ``foreach`` loop to iterate through +the returned cursor and display the contents of the files uploaded in the +:ref:`gridfs-upload-files` examples: + +.. io-code-block:: + :copyable: + + .. input:: /includes/write/gridfs.php + :start-after: start-retrieve-file-info + :end-before: end-retrieve-file-info + :language: php + :dedent: + + .. output:: + :visible: false + + { "_id" : { "$oid" : "..." }, "chunkSize" : 261120, "filename" : "my_file", + "length" : 13, "uploadDate" : { ... }, "metadata" : { "contentType" : "text/plain" }, + "md5" : "6b24249b03ea3dd176c5a04f037a658c" } + { "_id" : { "$oid" : "..." }, "chunkSize" : 261120, "filename" : "new_file", + "length" : 13, "uploadDate" : { ... }, "md5" : "6b24249b03ea3dd176c5a04f037a658c" } + +The ``find()`` method accepts various query specifications. You can use its +``$options`` parameter to specify the sort order, maximum number of documents to return, +and the number of documents to skip before returning. To view a list of available +options, see the `API documentation <{+api+}/method/MongoDBGridFSBucket-find/#parameters>`__. + +.. note:: + + The preceding example calls the ``toJSON()`` method to print file metadata as + Extended JSON, defined in the following code: + + .. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-to-json + :end-before: end-to-json + +.. _gridfs-download-files: + +Download Files +-------------- + +You can download files from a GridFS bucket by using the following methods: + +- ``MongoDB\GridFS\Bucket::openDownloadStreamByName()`` or + ``MongoDB\GridFS\Bucket::openDownloadStream()``: Opens a new download stream + from which you can read the file contents +- ``MongoDB\GridFS\Bucket::downloadToStream()``: Writes the entire file to + an existing download stream + +Read From a Download Stream +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can download files from your MongoDB database by using the +``MongoDB\GridFS\Bucket::openDownloadStreamByName()`` method to +create a download stream. + +This example uses a download stream to perform the following actions: + +- Selects a GridFS file named ``'my_file'``, uploaded in the + :ref:`gridfs-open-upload-stream` example, and opens it as a readable stream +- Calls the ``stream_get_contents()`` method to read the contents of ``'my_file'`` +- Prints the file contents +- Calls the ``fclose()`` method to close the download stream pointing to ``'my_file'`` + +.. io-code-block:: + :copyable: + + .. input:: /includes/write/gridfs.php + :start-after: start-open-download-stream-name + :end-before: end-open-download-stream-name + :language: php + :dedent: + + .. output:: + :visible: false + + "Data to store" + +.. note:: + + If there are multiple documents with the same file name, + GridFS will stream the most recent file with the given name (as + determined by the ``uploadDate`` field). + +Alternatively, you can use the ``MongoDB\GridFS\Bucket::openDownloadStream()`` +method, which takes the ``_id`` field of a file as a parameter: + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-download-files-id + :end-before: end-download-files-id + +.. note:: + + The GridFS streaming API cannot load partial chunks. When a download + stream needs to pull a chunk from MongoDB, it pulls the entire chunk + into memory. The 255-kilobyte default chunk size is usually + sufficient, but you can reduce the chunk size to reduce memory + overhead or increase the chunk size when working with larger files. + For more information about setting the chunk size, see the + :ref:`gridfs-create-custom-bucket` section of this page. + +Download a File Revision +~~~~~~~~~~~~~~~~~~~~~~~~ + +When your bucket contains multiple files that share the same file name, +GridFS chooses the most recently uploaded version of the file by default. +To differentiate between each file that shares the same name, GridFS assigns them +a revision number, ordered by upload time. + +The original file revision number is ``0`` and the next most recent file revision +number is ``1``. You can also specify negative values that correspond to the recency +of the revision. The revision value ``-1`` references the most recent revision and ``-2`` +references the next most recent revision. + +You can instruct GridFS to download a specific file revision by passing an options +array to the ``openDownloadStreamByName()`` method and specifying the ``revision`` +option. The following example reads the contents of the original file named +``'my_file'`` rather than the most recent revision: + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-download-file-revision + :end-before: end-download-file-revision + +Download to an Existing Stream +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can download the contents of a GridFS file to an existing stream +by calling the ``MongoDB\GridFS\Bucket::downloadToStream()`` method +on your bucket. + +This example performs the following actions: + +- Calls the ``fopen()`` method to open a file located at ``/path/to/output_file`` + as a stream in binary write (``wb``) mode +- Downloads a GridFS file that has an ``_id`` value of ``ObjectId('66e0a5487c880f844c0a32b1')`` + to the stream + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-download-to-stream + :end-before: end-download-to-stream + +.. _gridfs-rename-files: + +Rename Files +------------ + +Use the ``MongoDB\GridFS\Bucket::rename()`` method to update the name of +a GridFS file in your bucket. You must specify the file to rename by its +``_id`` field rather than its file name. + +The following example shows how to update the ``filename`` field to +``'new_file_name'`` by referencing a document's ``_id`` field: + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-rename-files + :end-before: end-rename-files + +.. note:: File Revisions + + The ``rename()`` method supports updating the name of only one file at + a time. If you want to rename each file revision, or files with different upload + times that share the same file name, collect the ``_id`` values of each revision. + Then, pass each value in separate calls to the ``rename()`` method. + +.. _gridfs-delete-files: + +Delete Files +------------ + +Use the ``MongoDB\GridFS\Bucket::delete()`` method to remove a file's collection +document and associated chunks from your bucket. This effectively deletes the file. +You must specify the file by its ``_id`` field rather than its file name. + +The following example shows you how to delete a file by referencing its ``_id`` field: + +.. literalinclude:: /includes/write/gridfs.php + :language: php + :dedent: + :start-after: start-delete-files + :end-before: end-delete-files + +.. note:: File Revisions + + The ``delete()`` method supports deleting only one file at a time. If + you want to delete each file revision, or files with different upload + times that share the same file name, collect the ``_id`` values of each revision. + Then, pass each value in separate calls to the ``delete()`` method. + +API Documentation +----------------- + +To learn more about using the {+php-library+} to store and retrieve large files, +see the following API documentation: + +- :phpmethod:`MongoDB\Database::selectGridFSBucket()` +- :phpmethod:`MongoDB\GridFS\Bucket::openUploadStream()` +- :phpmethod:`MongoDB\GridFS\Bucket::uploadFromStream()` +- :phpmethod:`MongoDB\GridFS\Bucket::find()` +- :phpmethod:`MongoDB\GridFS\Bucket::openDownloadStreamByName()` +- :phpmethod:`MongoDB\GridFS\Bucket::openDownloadStream()` +- :phpmethod:`MongoDB\GridFS\Bucket::downloadToStream()` +- :phpmethod:`MongoDB\GridFS\Bucket::rename()` +- :phpmethod:`MongoDB\GridFS\Bucket::delete()` \ No newline at end of file From 668f3dcc05516688c54c7fa125216aed60e63ccb Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Tue, 17 Sep 2024 11:22:44 -0400 Subject: [PATCH 060/149] DOCSP-41971: Bulk write (#130) * DOCSP-41971: Bulk write * edits * JS feedback * api links --- source/includes/write/bulk-write.php | 57 +++++++ source/tutorial/codecs.txt | 2 + source/write.txt | 7 +- source/write/bulk-write.txt | 230 +++++++++++++++++++++++++++ 4 files changed, 293 insertions(+), 3 deletions(-) create mode 100644 source/includes/write/bulk-write.php create mode 100644 source/write/bulk-write.txt diff --git a/source/includes/write/bulk-write.php b/source/includes/write/bulk-write.php new file mode 100644 index 00000000..a3543a22 --- /dev/null +++ b/source/includes/write/bulk-write.php @@ -0,0 +1,57 @@ +sample_restaurants->restaurants; +// end-db-coll + +// start-run-bulk +$result = $collection->bulkWrite( + [ + [ + 'insertOne' => [ + ['name' => 'Mongo\'s Deli'], + ['cuisine' => 'Sandwiches'], + ['borough' => 'Manhattan'], + ['restaurant_id' => '1234'], + ], + ], + [ + 'updateOne' => [ + ['name' => 'Mongo\'s Deli'], + ['$set' => ['cuisine' => 'Sandwiches and Salads']], + ], + ], + [ + 'deleteMany' => [ + ['borough' => 'Manhattan'], + ], + ], + ] +); +// end-run-bulk + +// start-bulk-options +$result = $collection->bulkWrite( + [ + [ + 'insertOne' => [ + ['name' => 'Mongo\'s Pizza'], + ['cuisine' => 'Italian'], + ['borough' => 'Queens'], + ['restaurant_id' => '5678'], + ], + ], + [ + 'deleteOne' => [ + ['restaurant_id' => '5678'], + ], + ], + ], + ['ordered' => false] +); +// end-bulk-options diff --git a/source/tutorial/codecs.txt b/source/tutorial/codecs.txt index a4bb5dd6..44a6f41f 100644 --- a/source/tutorial/codecs.txt +++ b/source/tutorial/codecs.txt @@ -1,3 +1,5 @@ +.. _php-codecs: + ====== Codecs ====== diff --git a/source/write.txt b/source/write.txt index 5ce877d9..ee30d336 100644 --- a/source/write.txt +++ b/source/write.txt @@ -21,11 +21,12 @@ Write Data to MongoDB .. toctree:: :titlesonly: :maxdepth: 1 - + + /write/update + /write/insert /write/delete /write/replace - /write/insert - /write/update + /write/bulk-write /write/gridfs Overview diff --git a/source/write/bulk-write.txt b/source/write/bulk-write.txt new file mode 100644 index 00000000..bf9abcec --- /dev/null +++ b/source/write/bulk-write.txt @@ -0,0 +1,230 @@ +.. _php-bulk-write: + +===================== +Bulk Write Operations +===================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: insert, update, replace, code example + +Overview +-------- + +In this guide, you can learn how to perform multiple write operations +in a single database call by using **bulk write operations**. + +Consider a scenario in which you want to insert a document into a collection, +update multiple other documents, then delete a document. If you use +individual methods, each operation requires its own database call. Instead, +you can use a bulk operation to reduce the number of calls to the database. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` +database from the :atlas:`Atlas sample datasets `. To access this collection +from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster +and assign the following value to your ``$collection`` variable: + +.. literalinclude:: /includes/write/bulk-write.php + :language: php + :dedent: + :start-after: start-db-coll + :end-before: end-db-coll + +To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the +:atlas:`Get Started with Atlas ` guide. + +.. _php-bulk-operations: + +Bulk Operations +--------------- + +To run a bulk write operation, pass an array of write operations to the +``MongoDB\Collection::bulkWrite()`` method. Use the following syntax to +specify the write operations: + +.. code-block:: php + + [ + [ 'deleteMany' => [ $filter ] ], + [ 'deleteOne' => [ $filter ] ], + [ 'insertOne' => [ $document ] ], + [ 'replaceOne' => [ $filter, $replacement, $options ] ], + [ 'updateMany' => [ $filter, $update, $options ] ], + [ 'updateOne' => [ $filter, $update, $options ] ], + ] + +.. tip:: + + For more information about delete, insert, replace, and update + operations, see the :ref:`Write operation guides `. + +When you call the ``bulkWrite()`` method, the library automatically runs the +write operations in the order they're specified in the array. To learn how to +instruct ``bulkWrite()`` to run the write operations in an arbitrary order, +see the :ref:`php-bulk-modify` section. + +Example +~~~~~~~ + +This example runs the following write operations on the ``restaurants`` +collection: + +- **Insert operation** to insert a document in which the ``name`` value is + ``'Mongo's Deli'`` + +- **Update operation** to update the ``cuisine`` field of a document in + which the ``name`` value is ``'Mongo's Deli'`` + +- **Delete operation** to delete all documents in which the ``borough`` value + is ``'Manhattan'`` + +.. literalinclude:: /includes/write/bulk-write.php + :start-after: start-run-bulk + :end-before: end-run-bulk + :language: php + :dedent: + +.. _php-bulk-modify: + +Modify Bulk Write Behavior +-------------------------- + +You can modify the behavior of the ``MongoDB\Collection::bulkWrite()`` method by +passing an array that specifies option values as a parameter. The following table +describes the options you can set in the array: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Option + - Description + + * - ``bypassDocumentValidation`` + - | Specifies whether the operation bypasses document validation. This lets you + modify documents that don't meet the schema validation requirements, if any + exist. For more information about schema validation, see :manual:`Schema + Validation ` in the {+mdb-server+} + manual. + | Defaults to ``false``. + + * - ``codec`` + - | Sets the codec to use for encoding or decoding documents. Bulk writes + use the codec for ``insertOne()`` and ``replaceOne()`` operations. + For more information, see the :ref:`php-codecs` guide. + + * - ``writeConcern`` + - | Sets the write concern for the operation. + For more information, see :manual:`Write Concern ` + in the {+mdb-server+} manual. + + * - ``let`` + - | Specifies a document with a list of values to improve operation readability. + Values must be constant or closed expressions that don't reference document + fields. For more information, see the :manual:`let statement + ` in the + {+mdb-server+} manual. + + * - ``ordered`` + - | If set to ``true``: when a single write fails, the operation stops without + performing the remaining writes and throws an exception. + | If set to ``false``: when a single write fails, the operation continues to + attempt the remaining write operations, if any, then throws an exception. + | Defaults to ``true``. + + * - ``comment`` + - | Attaches a comment to the operation. For more information, see the :manual:`insert command + fields ` guide in the + {+mdb-server+} manual. + + * - ``session`` + - | Specifies the client session to associate with the operation. + +The following example calls the ``bulkWrite()`` method to perform an +insert and delete operation and sets the ``ordered`` option to +``false``: + +.. literalinclude:: /includes/write/bulk-write.php + :start-after: start-bulk-options + :end-before: end-bulk-options + :language: php + :dedent: + +If the library runs the insert operation first, one document is deleted. +If it runs the delete operation first, no documents are deleted. + +.. note:: + + Unordered bulk operations do not guarantee order of execution. The order can + differ from the way you list them to optimize the runtime. + +.. _php-bulk-return-value: + +Return Value +------------ + +The ``MongoDB\Collection::bulkWrite()`` method returns a ``MongoDB\BulkWriteResult`` +object. This class contains the following member functions: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Function + - Description + + * - ``getDeletedCount()`` + - | Returns the number of documents deleted, if any. + + * - ``getInsertedCount()`` + - | Returns the number of documents inserted, if any. + + * - ``getInsertedIds()`` + - | Returns a map of ``_id`` field values for inserted documents, if any. + + * - ``getMatchedCount()`` + - | Returns the number of documents matched during update and replace + operations, if applicable. + + * - ``getModifiedCount()`` + - | Returns the number of documents modified, if any. + + * - ``getUpsertedCount()`` + - | Returns the number of documents upserted, if any. + + * - ``getUpsertedIds()`` + - | Returns a map of ``_id`` field values for upserted documents, if any. + + * - ``isAcknowledged()`` + - | Returns a boolean indicating whether the bulk operation was acknowledged. + +Additional Information +---------------------- + +To learn how to perform individual write operations, see the following guides: + +- :ref:`php-write-insert` +- :ref:`php-write-update` +- :ref:`php-write-delete` +- :ref:`php-write-replace` + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- :phpmethod:`MongoDB\Collection::bulkWrite()` +- :phpclass:`MongoDB\BulkWriteResult` \ No newline at end of file From 4adaec333c10cf607fa6109d9bfc1846b98a8af7 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 17 Sep 2024 11:28:33 -0400 Subject: [PATCH 061/149] DOCSP-41987: atlas search idx --- source/includes/indexes/indexes.php | 57 ++++++++++ source/indexes.txt | 6 +- source/indexes/atlas-search-index.txt | 148 ++++++++++++++++++++++++++ source/indexes/index-mgmt.txt | 3 +- source/indexes/single-field-index.txt | 4 +- 5 files changed, 211 insertions(+), 7 deletions(-) create mode 100644 source/indexes/atlas-search-index.txt diff --git a/source/includes/indexes/indexes.php b/source/includes/indexes/indexes.php index e8cc9382..235e3ee5 100644 --- a/source/includes/indexes/indexes.php +++ b/source/includes/indexes/indexes.php @@ -55,3 +55,60 @@ ); echo json_encode($document), PHP_EOL; // end-index-array-query + +// start-create-search-index +$indexName = $collection->createSearchIndex( + ['mappings' => ['dynamic' => true]], + ['name' => 'mySearchIdx'] +); +// end-create-search-index + +// start-create-search-indexes +$indexNames = $collection->createSearchIndexes( + [ + [ + 'name' => 'SearchIdx_dynamic', + 'definition' => ['mappings' => ['dynamic' => true]], + ], + [ + 'name' => 'SearchIdx_simple', + 'definition' => [ + 'mappings' => [ + 'dynamic' => false, + 'fields' => [ + 'title' => [ + 'type' => 'string', + 'analyzer' => 'lucene.simple' + ] + ] + ] + ], + ], + ] +); +// end-create-search-indexes + +// start-list-search-indexes +foreach ($collection->listSearchIndexes() as $indexInfo) { + echo json_encode($indexInfo), PHP_EOL; +} +// end-list-search-indexes + +// start-update-search-indexes +$collection->updateSearchIndex( + 'mySearchIdx', + ['mappings' => [ + 'dynamic' => false, + 'fields' => [ + 'title' => [ + 'type' => 'string', + 'analyzer' => 'lucene.simple' + ] + ] + ]] +); +// end-update-search-indexes + +// start-delete-search-index +$collection->dropSearchIndex('mySearchIdx'); +// end-delete-search-index \ No newline at end of file diff --git a/source/indexes.txt b/source/indexes.txt index 3aa04f52..5a3d884f 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -230,15 +230,15 @@ Atlas Search Index Management The following sections contain code examples that describe how to manage :atlas:`Atlas Search indexes `. -.. note:: Search Index Management is Asynchronous +.. note:: Atlas Search Index Management is Asynchronous The {+php-library+} manages Atlas Search indexes asynchronously. The library methods described in the following sections return the server response immediately, but the changes to your Search indexes take place in the background and might not complete until some time later. -.. To learn more about Atlas Search indexes, see the :ref:`php-atlas-search-index` -.. guide. +To learn more about Atlas Search indexes, see the :ref:`php-atlas-search-index` +guide. Create Search Index ~~~~~~~~~~~~~~~~~~~ diff --git a/source/indexes/atlas-search-index.txt b/source/indexes/atlas-search-index.txt new file mode 100644 index 00000000..cced5077 --- /dev/null +++ b/source/indexes/atlas-search-index.txt @@ -0,0 +1,148 @@ +.. _php-atlas-search-index: + +==================== +Atlas Search Indexes +==================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: index, query, text search, efficiency + +Overview +-------- + +The MongoDB Atlas Search feature enables you to perform full-text +searches on collections hosted on Atlas. The indexes specify the +behavior which fields to index and how they are indexed. + +To learn more about Atlas Search, see the :atlas:`Atlas Search Overview +`. + +You can use the following methods on a ``MongoDB\Collection`` instance +to manage your Atlas Search indexes: + +- ``MongoDB\Collection::createSearchIndex()`` +- ``MongoDB\Collection::createSearchIndexes()`` +- ``MongoDB\Collection::listSearchIndexes()`` +- ``MongoDB\Collection::updateSearchIndex()`` +- ``MongoDB\Collection::dropSearchIndex()`` + +.. note:: Atlas Search Index Management is Asynchronous + + The {+php-library+} manages Atlas Search indexes asynchronously. The + library methods described in the following sections return the server + response immediately, but the changes to your Search indexes take + place in the background and might not complete until some time later. + +The following sections provide code examples that demonstrate how to use +each Atlas Search index management method. + +.. _php-atlas-search-index-create: + +Create a Search Index +--------------------- + +You can use the ``createSearchIndex()`` method to create a single Atlas +Search index on a collection, or the ``createSearchIndexes()`` method to +create multiple indexes simultaneously. + +The following code example shows how to create a single Atlas Search +index: + +.. literalinclude:: /includes/indexes/indexes.php + :language: php + :start-after: start-create-search-index + :end-before: end-create-search-index + +The following code example shows how to create multiple Atlas Search +indexes: + +.. literalinclude:: /includes/indexes/indexes.php + :language: php + :start-after: start-create-search-indexes + :end-before: end-create-search-indexes + +After you create a Search index, you can perform Atlas Search queries on +your collection. To learn more, see :atlas:`Create and Run Atlas Search +Queries ` in the Atlas documentation. + +.. _php-atlas-search-index-list: + +List Search Indexes +------------------- + +You can use the ``listSearchIndexes()`` method to return an array of the +Atlas Search indexes on a collection: + +.. literalinclude:: /includes/indexes/indexes.php + :language: php + :dedent: + :start-after: start-list-search-indexes + :end-before: end-list-search-indexes + +.. _php-atlas-search-index-update: + +Update a Search Index +--------------------- + +You can use the ``updateSearchIndex()`` +method to update an Atlas Search index. You can use this method to +change the name of a Search index or change the configuration of the +index. + +The following code shows how to update a search index to use a simple +analyzer on the ``title`` field: + +.. literalinclude:: /includes/indexes/indexes.php + :language: php + :dedent: + :start-after: start-update-search-indexes + :end-before: end-update-search-indexes + +.. _php-atlas-search-index-drop: + +Delete a Search Index +--------------------- + +You can use the ``dropSearchIndex()`` method to remove an Atlas Search +index from a collection. + +The following code shows how to delete the Atlas Search index named +``mySearchIdx``: + +.. literalinclude:: /includes/indexes/indexes.php + :language: php + :dedent: + :start-after: start-delete-search-index + :end-before: end-delete-search-index + +Additional Information +---------------------- + +To view runnable examples that demonstrate how to manage indexes, see +:ref:`php-indexes`. + +To view tutorials that explain how to use the Atlas Search feature, see +:atlas:`Get Started with Atlas Search ` in the +Atlas documentation. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the methods discussed in this guide, see the +following API documentation: + +- :phpmethod:`MongoDB\Collection::createSearchIndex()` +- :phpmethod:`MongoDB\Collection::createSearchIndexes()` +- :phpmethod:`MongoDB\Collection::listSearchIndexes()` +- :phpmethod:`MongoDB\Collection::updateSearchIndex()` +- :phpmethod:`MongoDB\Collection::dropSearchIndex()` diff --git a/source/indexes/index-mgmt.txt b/source/indexes/index-mgmt.txt index adf19d9b..4d127e80 100644 --- a/source/indexes/index-mgmt.txt +++ b/source/indexes/index-mgmt.txt @@ -69,8 +69,7 @@ code to programmatically create each type of index. - :ref:`php-single-field-index` - :ref:`php-compound-index` - :ref:`php-multikey-index` - -.. - :ref:`php-atlas-search-index` +- :ref:`php-atlas-search-index` List Indexes ------------ diff --git a/source/indexes/single-field-index.txt b/source/indexes/single-field-index.txt index df137fb2..acffcb7a 100644 --- a/source/indexes/single-field-index.txt +++ b/source/indexes/single-field-index.txt @@ -92,8 +92,8 @@ Indexes ` in the {+mdb-server+} manual. API Documentation ~~~~~~~~~~~~~~~~~ -To learn more about any of the methods discussed in this guide, see the following API -documentation: +To learn more about any of the methods discussed in this guide, see the +following API documentation: - :phpmethod:`MongoDB\Collection::createIndex()` - :phpmethod:`MongoDB\Collection::findOne()` From 6df74fd50da1c9391008f8d5143ea7d3e96c7e6b Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 17 Sep 2024 11:32:00 -0400 Subject: [PATCH 062/149] resolve todos --- source/indexes.txt | 16 ++-------------- source/indexes/index-mgmt.txt | 2 ++ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/source/indexes.txt b/source/indexes.txt index 5a3d884f..80714006 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -221,8 +221,8 @@ The following example deletes an index with the specified name: :copyable: :dedent: -.. TODO: To learn more about removing indexes, see :ref:`php-indexes-remove` -.. in the Work with Indexes guide. +To learn more about deleting indexes, see :ref:`php-remove-idx` +in the Index Considerations and Management guide. Atlas Search Index Management ----------------------------- @@ -252,9 +252,6 @@ The following example creates an Atlas Search index on the specified field: :copyable: :dedent: -.. To learn more about creating search indexes, see the -.. :ref:`php-atlas-search-index-create` guide. - List Search Indexes ~~~~~~~~~~~~~~~~~~~ @@ -268,9 +265,6 @@ specified collection: :copyable: :dedent: -.. To learn more about listing search indexes, see the :ref:`php-atlas-search-index-list` -.. guide. - Update Search Indexes ~~~~~~~~~~~~~~~~~~~~~ @@ -284,9 +278,6 @@ new index definition: :copyable: :dedent: -.. To learn more about updating search indexes, see the :ref:`php-atlas-search-index-update` -.. guide. - Delete Search Indexes ~~~~~~~~~~~~~~~~~~~~~ @@ -298,6 +289,3 @@ The following example deletes an Atlas Search index with the specified name: :language: php :copyable: :dedent: - -.. To learn more about deleting search indexes, see the :ref:`php-atlas-search-index-drop` -.. guide. diff --git a/source/indexes/index-mgmt.txt b/source/indexes/index-mgmt.txt index 4d127e80..b56b8fa2 100644 --- a/source/indexes/index-mgmt.txt +++ b/source/indexes/index-mgmt.txt @@ -83,6 +83,8 @@ You can retrieve a list of indexes on a collection by calling the :end-before: end-list-indexes :dedent: +.. _php-remove-idx: + Remove an Index --------------- From 90abbca1ba6a4f4d530df79a5e938280d56c26c7 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 17 Sep 2024 11:36:14 -0400 Subject: [PATCH 063/149] toc --- snooty.toml | 1 + source/indexes.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/snooty.toml b/snooty.toml index 7f35dafe..c7c062de 100644 --- a/snooty.toml +++ b/snooty.toml @@ -19,6 +19,7 @@ toc_landing_pages = [ "/reference/class/MongoDBModelIndexInfo", "/get-started", "/write", + "/indexes" ] [substitutions] diff --git a/source/indexes.txt b/source/indexes.txt index 80714006..2e6d5ccf 100644 --- a/source/indexes.txt +++ b/source/indexes.txt @@ -26,6 +26,7 @@ Optimize Queries by Using Indexes /indexes/single-field-index /indexes/compound-index /indexes/multikey-index + /indexes/atlas-search-index Overview -------- From bde5e5942bf346396390932e4df3f89731f56c3d Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Tue, 17 Sep 2024 13:14:30 -0400 Subject: [PATCH 064/149] DOCSP-41963: Databases and collections (#136) * DOCSP-41963: Databases and collections * edits * phpmethod * code fix * MW feedback * fix * MW feedback 2 * JM feedback * JM feedback 2 --- source/databases-collections.txt | 322 ++++++++++++++++++ .../databases-collections.php | 105 ++++++ source/index.txt | 1 + 3 files changed, 428 insertions(+) create mode 100644 source/databases-collections.txt create mode 100644 source/includes/databases-collections/databases-collections.php diff --git a/source/databases-collections.txt b/source/databases-collections.txt new file mode 100644 index 00000000..1a650dc9 --- /dev/null +++ b/source/databases-collections.txt @@ -0,0 +1,322 @@ +.. _php-databases-collections: + +========================= +Databases and Collections +========================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: table, row, organize, storage, code example + +Overview +-------- + +In this guide, you can learn how to use MongoDB databases and +collections with the {+php-library+}. + +MongoDB organizes data into a hierarchy of the following levels: + +- **Databases**: Top-level data structures in a MongoDB deployment that store collections. +- **Collections**: Groups of MongoDB documents. They are analogous to tables in relational databases. +- **Documents**: Units that store literal data such as string, numbers, dates, and other embedded documents. + For more information about document field types and structure, see the + :manual:`Documents ` guide in the {+mdb-server+} manual. + +Access a Database +----------------- + +Access a database by passing the database name to the ``MongoDB\Client::selectDatabase()`` +method. + +The following example accesses a database named ``test_database``: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-access-database + :end-before: end-access-database + +Alternatively, you can implicitly call the ``MongoDB\Client::__get()`` magic method on +a client object. This method allows you to select a database by using the syntax for +accessing a class property. The following example uses this shorthand syntax to access +the ``test_database`` database: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-access-database-short + :end-before: end-access-database-short + +.. tip:: + + To learn more about ``__get()`` and PHP magic methods, see the following resources: + + - :phpmethod:`MongoDB\Client::__get()` in the API documentation + - `Magic Methods <{+php-manual+}/language.oop5.magic.php>`__ in the PHP manual + +.. _php-db-coll-access-collection: + +Access a Collection +------------------- + +Access a collection by using either of the following methods: + +- ``MongoDB\Client::selectCollection()``: Pass the database and collection names as + parameters +- ``MongoDB\Database::selectCollection()``: Pass the collection name as a parameter + +The following example accesses a collection named ``test_collection`` by using the +``MongoDB\Database::selectCollection()`` method: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-access-collection + :end-before: end-access-collection + +.. tip:: + + If the provided collection name does not already exist in the database, + MongoDB implicitly creates the collection when you first insert data + into it. + +Alternatively, you can implicitly call the ``MongoDB\Database::__get()`` magic method on +a database object. This method allows you to select a collection by using the syntax for +accessing a class property. The following example uses this shorthand syntax to access +the ``test_collection`` collection: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-access-collection-short + :end-before: end-access-collection-short + +To learn more, see the :phpmethod:`MongoDB\Database::__get()` +API documentation. + +.. _php-db-coll-create-collection: + +Create a Collection +------------------- + +Pass a collection name to the ``MongoDB\Database::createCollection()`` method to +explicitly create a collection in a MongoDB database. + +The following example creates a collection named ``example_collection``: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-create-collection + :end-before: end-create-collection + +You can specify collection options, such as maximum size and document +validation rules, by passing them as an array to the ``createCollection()`` method. +For a full list of optional parameters, see the `API documentation +<{+api+}/method/MongoDBDatabase-createCollection/#parameters>`__. + +Get a List of Collections +------------------------- + +You can query for a list of collections in a database by calling the +``MongoDB\Database::listCollections()`` method. The method returns a +cursor containing all collections in the database and their associated metadata. + +The following example calls the ``listCollections()`` method and iterates over +the returned iterator to print the collections from the :ref:`php-db-coll-access-collection` +and :ref:`php-db-coll-create-collection` examples: + +.. io-code-block:: + :copyable: + + .. input:: /includes/databases-collections/databases-collections.php + :language: php + :start-after: start-find-collections + :end-before: end-find-collections + :dedent: + + .. output:: + :language: console + :visible: false + + MongoDB\Model\CollectionInfo Object + ( + [name] => example_collection + [type] => collection + ... + ) + MongoDB\Model\CollectionInfo Object + ( + [name] => test_collection + [type] => collection + ... + ) + +Delete a Collection +------------------- + +You can delete a collection from the database by using the ``MongoDB\Database::dropCollection()`` +method. + +The following example deletes the ``test_collection`` collection: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-drop-collection + :end-before: end-drop-collection + +.. warning:: Dropping a Collection Deletes All Data in the Collection + + Dropping a collection from your database permanently deletes all + documents and all indexes within that collection. + + Drop a collection only if you no longer need the data in it. + +.. _php-config-read-write: + +Configure Read and Write Operations +----------------------------------- + +You can control how the library routes read operations by setting a **read preference**. +You can also control options for how the library waits for acknowledgment of +read and write operations on a replica set by setting a **read concern** and a +**write concern**. + +By default, databases inherit read and write settings from the ``MongoDB\Client`` +instance. Collections inherit these settings from the ``MongoDB\Client`` or +``MongoDB\Database`` instance on which the ``selectCollection()`` method is called. +You can change these settings by passing an options array to the +``MongoDB\Client::selectDatabase()``, ``MongoDB\Client::selectCollection()``, or +``MongoDB\Database::selectCollection()`` methods. + +To change the read preference, read concern, and write concern of your database +or collection, set the following options in the array parameter: + +- ``readPreference``: Sets the read preference. For a list of available read + preferences, see :php:`MongoDB\Driver\ReadPreference ` + in the extension API documentation. +- ``readConcern``: Sets the read concern. For a list of available read + concerns, see :php:`MongoDB\Driver\ReadConcern ` + in the extension API documentation. +- ``writeConcern``: Sets the write concern. For a list of available write + concerns, see :php:`MongoDB\Driver\WriteConcern ` + in the extension API documentation. + +.. tip:: + + To learn more about read preferences and read and write concerns, see the + following guides in the MongoDB Server manual: + + - :manual:`Read Preference ` + - :manual:`Read Concern ` + - :manual:`Write Concern ` + +Database Configuration Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example shows how to set the read preference, read concern, and +write concern of a database called ``test_database`` by passing an options +array to ``selectDatabase()``: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-database-settings + :end-before: end-database-settings + +Collection Configuration Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example shows how to set the read preference, read concern, and +write concern of a collection called ``test_collection`` by passing an options +array to ``selectCollection()``: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-collection-settings + :end-before: end-collection-settings + +Advanced Read Configurations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tag Sets +```````` + +In {+mdb-server+}, you can apply key-value :manual:`tags +` to replica-set +members according to any criteria you choose. You can then use +those tags to target one or more members for a read operation. + +By default, the {+php-library+} ignores tags when choosing a member +to read from. To instruct the {+php-library+} to prefer certain tags, +pass them as a parameter to your ``MongoDB\Driver\ReadPreference`` class +constructor. Then, set the ``MongoDB\Driver\ReadPreference`` object as +the value of the ``readPreference`` database option. + +This code example sets the ``readPreference`` option to a tag set +that instructs ``test_database`` to prefer reads from secondary replica set +members in the following order: + +1. Members from the New York data center (``['dc' => 'ny']``) +#. Members from the San Francisco data center (``['dc' => 'sf']``) +#. Any secondary members (``[]``) + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-tag-set + :end-before: end-tag-set + +Local Threshold +``````````````` + +If multiple replica-set members match the read preference and tag sets you specify, +the {+php-library+} reads from the nearest replica-set members, chosen according to +their ping time. + +By default, the library uses only members whose ping times are within 15 milliseconds +of the nearest member for queries. To distribute reads between members with +higher latencies, pass an options array to the ``MongoDB\Client`` constructor that +sets the ``localThresholdMS`` option. + +The following example specifies a local threshold of 35 milliseconds: + +.. literalinclude:: /includes/databases-collections/databases-collections.php + :language: php + :dedent: + :start-after: start-local-threshold + :end-before: end-local-threshold + +In the preceding example, the {+php-library+} distributes reads among matching members +within 35 milliseconds of the closest member's ping time. + +.. note:: + + The {+php-library+} ignores the value of ``localThresholdMS`` when communicating with a + replica set through a ``mongos`` instance. In this case, use the + :manual:`localThreshold ` + command-line option. + +API Documentation +----------------- + +To learn more about any of the methods or types discussed in this +guide, see the following API documentation: + +- :phpmethod:`MongoDB\Client::selectDatabase()` +- :phpmethod:`MongoDB\Client::selectCollection()` +- :phpmethod:`MongoDB\Database::selectCollection()` +- :phpmethod:`MongoDB\Database::createCollection()` +- :phpmethod:`MongoDB\Database::listCollections()` +- :phpmethod:`MongoDB\Database::dropCollection()` \ No newline at end of file diff --git a/source/includes/databases-collections/databases-collections.php b/source/includes/databases-collections/databases-collections.php new file mode 100644 index 00000000..eb4dde74 --- /dev/null +++ b/source/includes/databases-collections/databases-collections.php @@ -0,0 +1,105 @@ +selectDatabase('test_database'); +// end-access-database + +// Invokes the __get() method to access the "test_database" database +// start-access-database-short +$db = $client->test_database; +// end-access-database-short + +// Accesses the "test_collection" collection +// start-access-collection +$collection = $client->test_database->selectCollection('test_collection'); +// end-access-collection + +// Invokes the __get() method to access the "test_collection" collection +// start-access-collection-short +$collection = $db->test_collection; +// end-access-collection-short + +// Explicitly creates the "example_collection" collection +// start-create-collection +$result = $client->test_database->createCollection('example_collection'); +// end-create-collection + +// Lists the collections in the "test_database" database +// start-find-collections +foreach ($client->test_database->listCollections() as $collectionInfo) { + print_r($collectionInfo) . PHP_EOL; +} +// end-find-collections + +// Deletes the "test_collection" collection +// start-drop-collection +$client->test_database->dropCollection('test_collection'); +// end-drop-collection + +// Sets read and write settings for the "test_database" database +// start-database-settings +$readPreference = new ReadPreference(ReadPreference::RP_SECONDARY); +$readConcern = new ReadConcern(ReadConcern::LOCAL); +$writeConcern = new WriteConcern(WriteConcern::MAJORITY); + +$db = $client->selectDatabase('test_database', [ + 'readPreference' => $readPreference, + 'readConcern' => $readConcern, + 'writeConcern' => $writeConcern, +]); +// end-database-settings + +// Sets read and write settings for the "test_collection" collection +// start-collection-settings +$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY); +$readConcern = new ReadConcern(ReadConcern::AVAILABLE); +$writeConcern = new WriteConcern(WriteConcern::MAJORITY); + +$collection = $client->selectCollection('test_database', 'test_collection', [ + 'readPreference' => $readPreference, + 'readConcern' => $readConcern, + 'writeConcern' => $writeConcern, +]); + +// end-collection-settings + +// Instructs the library to prefer reads from secondary replica set members +// located in New York, followed by a secondary in San Francisco, and +// lastly fall back to any secondary. +// start-tag-set +$readPreference = new ReadPreference( + ReadPreference::RP_SECONDARY, + [ + ['dc' => 'ny'], + ['dc' => 'sf'], + [], + ], +); + +$db = $client->selectDatabase( + 'test_database', + ['readPreference' => $readPreference], +); + +// end-tag-set + +// Instructs the library to distribute reads between members within 35 milliseconds +// of the closest member's ping time +// start-local-threshold +$options = [ + 'replicaSet' => 'repl0', + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'localThresholdMS' => 35, +]; + +$client = new Client('', [], $options); +// end-local-threshold diff --git a/source/index.txt b/source/index.txt index 707a62d2..95e744a0 100644 --- a/source/index.txt +++ b/source/index.txt @@ -11,6 +11,7 @@ MongoDB PHP Library :titlesonly: Get Started + /databases-collections /read /write /aggregation From 61fba292f96d51d80d119434ece7328d8870e89e Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 17 Sep 2024 16:24:25 -0400 Subject: [PATCH 065/149] JS fix --- source/indexes/atlas-search-index.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/indexes/atlas-search-index.txt b/source/indexes/atlas-search-index.txt index cced5077..eb8762aa 100644 --- a/source/indexes/atlas-search-index.txt +++ b/source/indexes/atlas-search-index.txt @@ -21,8 +21,9 @@ Overview -------- The MongoDB Atlas Search feature enables you to perform full-text -searches on collections hosted on Atlas. The indexes specify the -behavior which fields to index and how they are indexed. +searches on collections hosted on Atlas. Before you can perform Atlas +Search queries, you must create indexes that specify which +fields to index and how they are indexed. To learn more about Atlas Search, see the :atlas:`Atlas Search Overview `. From 1524f1132aab81ab224fe32ecaf864c713b09719 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Tue, 17 Sep 2024 17:28:37 -0400 Subject: [PATCH 066/149] internal review --- snooty.toml | 6 +++++- source/compatibility.txt | 21 +++++++++---------- .../language-compatibility-table-php.rst | 2 -- .../mongodb-compatibility-table-php.rst | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/snooty.toml b/snooty.toml index a074aa74..5fdba324 100644 --- a/snooty.toml +++ b/snooty.toml @@ -1,7 +1,11 @@ name = "php-library" title = "PHP Library Manual" -intersphinx = ["https://www.mongodb.com/docs/manual/objects.inv"] +intersphinx = [ + "https://www.mongodb.com/docs/manual/objects.inv", + "https://www.mongodb.com/docs/drivers/objects.inv", + "https://www.mongodb.com/docs/atlas/objects.inv", +] toc_landing_pages = [ "/reference/class/MongoDBClient", diff --git a/source/compatibility.txt b/source/compatibility.txt index 79d11bb4..30324322 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -21,31 +21,31 @@ MongoDB Compatibility --------------------- The following compatibility table specifies the recommended version or versions -of the PHP driver for use with a specific version of MongoDB. +of the {+php-library+} and extension that you can use with a specific version of MongoDB. -The first column lists the driver version. +The first column lists the version of the library and extension. .. sharedinclude:: dbx/lifecycle-schedule-callout.rst .. include:: /includes/mongodb-compatibility-table-php.rst For more information on how to read the compatibility tables, see our guide on -`MongoDB Compatibility Tables `__. +`MongoDB Compatibility Tables `__. Language Compatibility ---------------------- The following compatibility table specifies the recommended version or versions -of the PHP driver for use with a specific version of PHP. +of the {+php-library+} and extension that you can use with a specific version of PHP. -The first column lists the driver versions. +The first column lists the version of the library and extension. .. include:: /includes/language-compatibility-table-php.rst .. sharedinclude:: dbx/about-driver-compatibility.rst For more information on how to read the compatibility tables, see our guide on -`MongoDB Compatibility Tables `__. +`MongoDB Compatibility Tables `__. How to Get Help --------------- @@ -54,8 +54,7 @@ If you have questions about compatibility, visit the following resources for fur - Ask questions on our :community-forum:`MongoDB Community Forums <>`. - Visit our :technical-support:`Support Channels `. -- File an issue or feature request in JIRA under one of the following: - - - `Extension `_ - - - `Library `_ \ No newline at end of file +- File an issue or feature request in our issue tracker, JIRA, under one of the + following projects:: + - `PHPC - Extension `_ + - `PHPLIB - Library `_ \ No newline at end of file diff --git a/source/includes/language-compatibility-table-php.rst b/source/includes/language-compatibility-table-php.rst index 50319621..c1d961f1 100644 --- a/source/includes/language-compatibility-table-php.rst +++ b/source/includes/language-compatibility-table-php.rst @@ -1,5 +1,3 @@ -.. sharedinclude:: dbx/compatibility-table-legend.rst - .. list-table:: :header-rows: 1 :stub-columns: 1 diff --git a/source/includes/mongodb-compatibility-table-php.rst b/source/includes/mongodb-compatibility-table-php.rst index 82a9c271..807b7979 100644 --- a/source/includes/mongodb-compatibility-table-php.rst +++ b/source/includes/mongodb-compatibility-table-php.rst @@ -214,7 +214,7 @@ - - -.. [#PHP1.15-version-parity] Version 1.14 of the MongoDB PHP library has been +.. [#PHP1.15-version-parity] Version 1.14 of the {+php-library+} has been skipped to restore version parity between the library and extension. .. [#PHPC1.10-PHPLIB1.9-driver-support] The extension 1.10 + library 1.9 From 5dcbd1593b88377b3a638430b2f6a6625b1a46f7 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 17 Sep 2024 14:34:05 -0400 Subject: [PATCH 067/149] DOCSP-41982: cluster monitoring --- source/includes/monitoring/sdam.php | 44 ++++++++ source/index.txt | 1 + source/monitoring.txt | 21 ++++ source/monitoring/cluster-monitoring.txt | 134 +++++++++++++++++++++++ 4 files changed, 200 insertions(+) create mode 100644 source/includes/monitoring/sdam.php create mode 100644 source/monitoring.txt create mode 100644 source/monitoring/cluster-monitoring.txt diff --git a/source/includes/monitoring/sdam.php b/source/includes/monitoring/sdam.php new file mode 100644 index 00000000..02d17c91 --- /dev/null +++ b/source/includes/monitoring/sdam.php @@ -0,0 +1,44 @@ +stream = $stream; + } + public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void + { + fwrite($this->stream, sprintf( + 'Server opening on %s:%s%s', + $event->getHost(), + $event->getPort(), + PHP_EOL, + )); + } + public function serverClosed(MongoDB\Driver\Monitoring\ServerClosedEvent $event): void {} + public function serverChanged(MongoDB\Driver\Monitoring\ServerChangedEvent $event): void {} + public function serverHeartbeatFailed(MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent $event): void {} + public function serverHeartbeatStarted(MongoDB\Driver\Monitoring\ServerHeartbeatStartedEvent $event): void {} + public function serverHeartbeatSucceeded(MongoDB\Driver\Monitoring\ServerHeartbeatSucceededEvent $event): void {} + public function topologyChanged(MongoDB\Driver\Monitoring\TopologyChangedEvent $event): void {} + public function topologyClosed(MongoDB\Driver\Monitoring\TopologyClosedEvent $event): void {} + public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $event): void {} +} +// end-mysubscriber + +$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your Atlas URI that connects to the sample dataset'); +$client = new MongoDB\Client($uri); + +$database = $client->db; +$collection = $database->my_coll; + +// start-add-sub +$subscriber = new MySubscriber(STDERR); +$client->addSubscriber($subscriber); +// end-add-sub + +$collection->insertOne(['x' => 100]); diff --git a/source/index.txt b/source/index.txt index 95e744a0..042021d3 100644 --- a/source/index.txt +++ b/source/index.txt @@ -16,6 +16,7 @@ MongoDB PHP Library /write /aggregation /indexes + /monitoring /security /tutorial /upgrade diff --git a/source/monitoring.txt b/source/monitoring.txt new file mode 100644 index 00000000..4a6d1191 --- /dev/null +++ b/source/monitoring.txt @@ -0,0 +1,21 @@ +.. _php-monitoring: + +======================== +Monitor Your Application +======================== + +.. toctree:: + :caption: Monitoring categories + + /monitoring/cluster-monitoring + +.. /monitoring/command-monitoring +.. /monitoring/connection-monitoring + +- :ref:`Cluster Monitoring `: monitor changes + in your cluster configuration + +.. TODO - :ref:`Command Monitoring `: monitor command +.. execution +.. - :ref:`Connection Pool Monitoring `: +.. monitor changes in the connection pool \ No newline at end of file diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt new file mode 100644 index 00000000..fa503e06 --- /dev/null +++ b/source/monitoring/cluster-monitoring.txt @@ -0,0 +1,134 @@ +.. _php-cluster-monitoring: + +================== +Cluster Monitoring +================== + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, server, topology + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecols + +Overview +-------- + +This guide shows you how to use the {+php-library+} to monitor topology +events in a MongoDB instance, replica set, or sharded cluster. The +driver creates topology events, also known as Server Discovery and +Monitoring (**SDAM**) events, when there are any changes in the state of the +MongoDB instance or cluster that you are connected to. + +You might use information about topology events in your +application to understand cluster changes, assess cluster health, or +perform capacity planning. + +Subscribe to Events +------------------- + +You can access details about SDAM events by subscribing to them +in your application. To subscribe to any event, create a class that +implements the ``MongoDB\Driver\Monitoring\SDAMSubscriber`` interface, +then use the ``MongoDB\Client::addSubscriber()`` method to register the +event subscriber with your ``MongoDB\Client`` instance. + +The following code creates the ``MySubscriber`` class that implements +``SDAMSubscriber`` to output a message when a ``ServerOpeningEvent`` is +generated by the server: + +.. literalinclude:: /includes/monitoring/sdam.php + :start-after: start-mysubscriber + :end-before: end-mysubscriber + :language: php + :copyable: + :dedent: + +.. note:: + + As shown in the preceding code, you must implement all of the methods + of ``SDAMSubscriber``, even for events you are not subscribing to. + You can implement these methods with empty bodies so that the library + does not generate any messages for these events. + +Then, the following code uses the ``addSubscriber()`` method to register +``MySubscriber`` with the client: + +.. literalinclude:: /includes/monitoring/sdam.php + :start-after: start-add-sub + :end-before: end-add-sub + :language: php + :copyable: + :dedent: + +When you run the application, your subscriber records the SDAM event and +outputs messages such as the following: + +.. code-block:: none + + Server opening on ac-rmuag0v-shard-00-00.gh0qg50.mongodb.net:27017 + Server opening on ac-rmuag0v-shard-00-01.gh0qg50.mongodb.net:27017 + Server opening on ac-rmuag0v-shard-00-02.gh0qg50.mongodb.net:27017 + +Event Descriptions +------------------ + +You can subscribe to the following SDAM events by implementing the +corresponding method from the ``SDAMSubscriber`` interface: + +.. list-table:: + :widths: 35 65 + :header-rows: 1 + + * - Event Name + - Description + + * - ``ServerChangedEvent`` + - Created when an instance state changes, such as from secondary to + primary. + + * - ``ServerOpeningEvent`` + - Created when the server is initialized. + + * - ``ServerClosedEvent`` + - Created when the server is closed. + + * - ``TopologyChangedEvent`` + - Created when the topology changes, such as an election of a new + primary or disconnection of a ``mongos`` proxy. + + * - ``TopologyOpeningEvent`` + - Created when the topology is initialized. + + * - ``TopologyClosedEvent`` + - Created when the topology is closed. + + * - ``ServerHeartbeatStartedEvent`` + - Created when the heartbeat is started. + + * - ``ServerHeartbeatSucceededEvent`` + - Created when the heartbeat succeeds. + + * - ``ServerHeartbeatFailedEvent`` + - Created when the heartbeat fails. + +API Documentation +----------------- + +To learn more about any of the classes or methods discussed in this guide, see the +following API documentation: + +- :phpmethod:`MongoDB\Client::addSubscriber()` +- :phpclass:`MongoDB\Client` + +To learn more about subscriber classes and methods, see the following +pages in the PHP manual: + +- :php:`mongodb-driver-monitoring-sdamsubscriber` +- :php:`mongodb-driver-monitoring-serveropeningevent` From 564dfe9337ac3b12a257d92978fcff9fccb837e4 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 17 Sep 2024 15:34:44 -0400 Subject: [PATCH 068/149] small fixes --- source/monitoring/cluster-monitoring.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt index fa503e06..02e23617 100644 --- a/source/monitoring/cluster-monitoring.txt +++ b/source/monitoring/cluster-monitoring.txt @@ -71,6 +71,7 @@ When you run the application, your subscriber records the SDAM event and outputs messages such as the following: .. code-block:: none + :copyable: false Server opening on ac-rmuag0v-shard-00-00.gh0qg50.mongodb.net:27017 Server opening on ac-rmuag0v-shard-00-01.gh0qg50.mongodb.net:27017 @@ -130,5 +131,5 @@ following API documentation: To learn more about subscriber classes and methods, see the following pages in the PHP manual: -- :php:`mongodb-driver-monitoring-sdamsubscriber` -- :php:`mongodb-driver-monitoring-serveropeningevent` +- :php:`MongoDB\Driver\Monitoring\SDAMSubscriber ` +- :php:`MongoDB\Driver\Monitoring\ServerOpeningEvent ` From fce89723c2998373421c916b35cc6f0a5db53a3c Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 18 Sep 2024 09:33:35 -0400 Subject: [PATCH 069/149] MW PR fixes 1 --- source/monitoring.txt | 2 +- source/monitoring/cluster-monitoring.txt | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/source/monitoring.txt b/source/monitoring.txt index 4a6d1191..5322004f 100644 --- a/source/monitoring.txt +++ b/source/monitoring.txt @@ -12,7 +12,7 @@ Monitor Your Application .. /monitoring/command-monitoring .. /monitoring/connection-monitoring -- :ref:`Cluster Monitoring `: monitor changes +- :ref:`Cluster Monitoring `: Monitor changes in your cluster configuration .. TODO - :ref:`Command Monitoring `: monitor command diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt index 02e23617..04d291b4 100644 --- a/source/monitoring/cluster-monitoring.txt +++ b/source/monitoring/cluster-monitoring.txt @@ -23,7 +23,7 @@ Overview This guide shows you how to use the {+php-library+} to monitor topology events in a MongoDB instance, replica set, or sharded cluster. The driver creates topology events, also known as Server Discovery and -Monitoring (**SDAM**) events, when there are any changes in the state of the +Monitoring (SDAM) events, when there are any changes in the state of the MongoDB instance or cluster that you are connected to. You might use information about topology events in your @@ -34,14 +34,15 @@ Subscribe to Events ------------------- You can access details about SDAM events by subscribing to them -in your application. To subscribe to any event, create a class that +in your application. To subscribe to an event, create a class that implements the ``MongoDB\Driver\Monitoring\SDAMSubscriber`` interface, then use the ``MongoDB\Client::addSubscriber()`` method to register the event subscriber with your ``MongoDB\Client`` instance. -The following code creates the ``MySubscriber`` class that implements -``SDAMSubscriber`` to output a message when a ``ServerOpeningEvent`` is -generated by the server: +The following code creates the ``MySubscriber`` class, which implements +the ``SDAMSubscriber`` interface. The class is defined with a method to +output a message when a ``ServerOpeningEvent`` is generated by the +server: .. literalinclude:: /includes/monitoring/sdam.php :start-after: start-mysubscriber @@ -53,12 +54,12 @@ generated by the server: .. note:: As shown in the preceding code, you must implement all of the methods - of ``SDAMSubscriber``, even for events you are not subscribing to. + of the ``SDAMSubscriber`` interface, even for events you are not subscribing to. You can implement these methods with empty bodies so that the library does not generate any messages for these events. -Then, the following code uses the ``addSubscriber()`` method to register -``MySubscriber`` with the client: +Then, use the ``addSubscriber()`` method to register ``MySubscriber`` +with the client, as shown in the following code: .. literalinclude:: /includes/monitoring/sdam.php :start-after: start-add-sub From ba51cd64224408fa5fdbcb6f5d6e0a5d65c8b291 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 18 Sep 2024 13:26:19 -0400 Subject: [PATCH 070/149] test netlify --- source/compatibility.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/compatibility.txt b/source/compatibility.txt index 30324322..a3b324bc 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -47,7 +47,7 @@ The first column lists the version of the library and extension. For more information on how to read the compatibility tables, see our guide on `MongoDB Compatibility Tables `__. -How to Get Help +How To Get Help --------------- If you have questions about compatibility, visit the following resources for further guidance: From 13d165127402b8eac1693e5fdfeb5895299f305d Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 18 Sep 2024 13:39:19 -0400 Subject: [PATCH 071/149] spacing --- source/compatibility.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/compatibility.txt b/source/compatibility.txt index a3b324bc..dce18d4e 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -47,7 +47,7 @@ The first column lists the version of the library and extension. For more information on how to read the compatibility tables, see our guide on `MongoDB Compatibility Tables `__. -How To Get Help +How to Get Help --------------- If you have questions about compatibility, visit the following resources for further guidance: @@ -55,6 +55,8 @@ If you have questions about compatibility, visit the following resources for fur - Ask questions on our :community-forum:`MongoDB Community Forums <>`. - Visit our :technical-support:`Support Channels `. - File an issue or feature request in our issue tracker, JIRA, under one of the - following projects:: + following projects: + - `PHPC - Extension `_ + - `PHPLIB - Library `_ \ No newline at end of file From f8c0b5e8b190e7a6261d9a622a782bc4fc6098b5 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 18 Sep 2024 14:57:27 -0400 Subject: [PATCH 072/149] try using out of repo ref and add back legend --- source/compatibility.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/compatibility.txt b/source/compatibility.txt index dce18d4e..b162be2f 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -27,10 +27,12 @@ The first column lists the version of the library and extension. .. sharedinclude:: dbx/lifecycle-schedule-callout.rst +.. sharedinclude:: dbx/compatibility-table-legend.rst + .. include:: /includes/mongodb-compatibility-table-php.rst For more information on how to read the compatibility tables, see our guide on -`MongoDB Compatibility Tables `__. +:ref:`MongoDB Compatibility Tables. `. Language Compatibility ---------------------- From 321c3dd4b2bfce833168615016d37ed25ac3e924 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 18 Sep 2024 15:03:16 -0400 Subject: [PATCH 073/149] ou of repo ref --- source/compatibility.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/compatibility.txt b/source/compatibility.txt index b162be2f..e00d461a 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -27,12 +27,10 @@ The first column lists the version of the library and extension. .. sharedinclude:: dbx/lifecycle-schedule-callout.rst -.. sharedinclude:: dbx/compatibility-table-legend.rst - .. include:: /includes/mongodb-compatibility-table-php.rst For more information on how to read the compatibility tables, see our guide on -:ref:`MongoDB Compatibility Tables. `. +:ref:`MongoDB Compatibility Tables `. Language Compatibility ---------------------- @@ -47,7 +45,7 @@ The first column lists the version of the library and extension. .. sharedinclude:: dbx/about-driver-compatibility.rst For more information on how to read the compatibility tables, see our guide on -`MongoDB Compatibility Tables `__. +:ref:`MongoDB Compatibility Tables `. How to Get Help --------------- @@ -61,4 +59,5 @@ If you have questions about compatibility, visit the following resources for fur - `PHPC - Extension `_ - - `PHPLIB - Library `_ \ No newline at end of file + - `PHPLIB - Library `_ + \ No newline at end of file From 26d4a5ee49527154b919564dc65c6a6dcca9b6f3 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 18 Sep 2024 15:51:32 -0400 Subject: [PATCH 074/149] legend glitch --- source/compatibility.txt | 3 ++- source/includes/mongodb-compatibility-table-php.rst | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/source/compatibility.txt b/source/compatibility.txt index e00d461a..b3362b5a 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -27,6 +27,8 @@ The first column lists the version of the library and extension. .. sharedinclude:: dbx/lifecycle-schedule-callout.rst +.. sharedinclude:: dbx/compatibility-table-legend.rst + .. include:: /includes/mongodb-compatibility-table-php.rst For more information on how to read the compatibility tables, see our guide on @@ -60,4 +62,3 @@ If you have questions about compatibility, visit the following resources for fur - `PHPC - Extension `_ - `PHPLIB - Library `_ - \ No newline at end of file diff --git a/source/includes/mongodb-compatibility-table-php.rst b/source/includes/mongodb-compatibility-table-php.rst index 807b7979..9900ded2 100644 --- a/source/includes/mongodb-compatibility-table-php.rst +++ b/source/includes/mongodb-compatibility-table-php.rst @@ -1,5 +1,3 @@ -.. sharedinclude:: dbx/compatibility-table-legend.rst - .. list-table:: :header-rows: 1 :stub-columns: 1 From 9dfc72a66a17694788784e9f06a1f4ea0d557a5f Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 19 Sep 2024 13:42:04 -0400 Subject: [PATCH 075/149] JM tech review 1 --- source/includes/monitoring/sdam.php | 27 +++++--- source/monitoring/cluster-monitoring.txt | 88 ++++++++++++++++-------- 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/source/includes/monitoring/sdam.php b/source/includes/monitoring/sdam.php index 02d17c91..8760ec5e 100644 --- a/source/includes/monitoring/sdam.php +++ b/source/includes/monitoring/sdam.php @@ -1,24 +1,26 @@ stream = $stream; } - public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void - { - fwrite($this->stream, sprintf( - 'Server opening on %s:%s%s', + + public function serverOpening(MongoDB\Driver\Monitoring\ServerOpeningEvent $event): void { + fprintf( + $this->stream, + "Server opening on %s:%s\n", $event->getHost(), $event->getPort(), - PHP_EOL, - )); + ); } + public function serverClosed(MongoDB\Driver\Monitoring\ServerClosedEvent $event): void {} public function serverChanged(MongoDB\Driver\Monitoring\ServerChangedEvent $event): void {} public function serverHeartbeatFailed(MongoDB\Driver\Monitoring\ServerHeartbeatFailedEvent $event): void {} @@ -30,15 +32,18 @@ public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $ } // end-mysubscriber -$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your Atlas URI that connects to the sample dataset'); +$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your connection URI'); $client = new MongoDB\Client($uri); -$database = $client->db; -$collection = $database->my_coll; +$collection = $client->db->my_coll; // start-add-sub $subscriber = new MySubscriber(STDERR); $client->addSubscriber($subscriber); // end-add-sub -$collection->insertOne(['x' => 100]); +$collection->insertOne(["x" => 100]); + +// start-remove-sub +$client->removeSubscriber($subscriber); +// end-remove-sub \ No newline at end of file diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt index 04d291b4..8c0aa8df 100644 --- a/source/monitoring/cluster-monitoring.txt +++ b/source/monitoring/cluster-monitoring.txt @@ -20,15 +20,17 @@ Cluster Monitoring Overview -------- -This guide shows you how to use the {+php-library+} to monitor topology -events in a MongoDB instance, replica set, or sharded cluster. The -driver creates topology events, also known as Server Discovery and -Monitoring (SDAM) events, when there are any changes in the state of the -MongoDB instance or cluster that you are connected to. +This guide shows you how to use the {+php-library+} to monitor server +discovery and monitoring (SDAM) events in a MongoDB instance, replica +set, or sharded cluster. These events occur when there +are any changes in the state of the MongoDB instance or cluster that you +are connected to. -You might use information about topology events in your -application to understand cluster changes, assess cluster health, or -perform capacity planning. +You might use information about SDAM events in your application to +understand cluster changes, assess cluster health, or perform capacity +planning. + +.. _php-subscribe-sdam: Subscribe to Events ------------------- @@ -55,8 +57,8 @@ server: As shown in the preceding code, you must implement all of the methods of the ``SDAMSubscriber`` interface, even for events you are not subscribing to. - You can implement these methods with empty bodies so that the library - does not generate any messages for these events. + The example defines the extra methods as empty so that the + application does not output any messages for those events. Then, use the ``addSubscriber()`` method to register ``MySubscriber`` with the client, as shown in the following code: @@ -81,45 +83,71 @@ outputs messages such as the following: Event Descriptions ------------------ -You can subscribe to the following SDAM events by implementing the -corresponding method from the ``SDAMSubscriber`` interface: +You can subscribe to SDAM events by implementing the corresponding +method from the ``SDAMSubscriber`` interface. The following table +provides the name of each SDAM event, linked to the class's API +documentation, and a description of when the event is published: .. list-table:: :widths: 35 65 :header-rows: 1 - * - Event Name + * - Event Type - Description - * - ``ServerChangedEvent`` - - Created when an instance state changes, such as from secondary to - primary. + * - :php:`ServerChangedEvent ` + - Created when the server description changes, such as the server's type + changing from secondary to primary. - * - ``ServerOpeningEvent`` - - Created when the server is initialized. + * - :php:`ServerOpeningEvent ` + - Created when the server description is instantiated with its + defaults. - * - ``ServerClosedEvent`` + * - :php:`ServerClosedEvent ` - Created when the server is closed. - * - ``TopologyChangedEvent`` - - Created when the topology changes, such as an election of a new - primary or disconnection of a ``mongos`` proxy. + * - :php:`TopologyChangedEvent ` + - Created when the topology description changes, such when there is + an election of a new primary or disconnection of a ``mongos`` proxy. - * - ``TopologyOpeningEvent`` - - Created when the topology is initialized. + * - :php:`TopologyOpeningEvent ` + - Created when the topology description is initialized. - * - ``TopologyClosedEvent`` + * - :php:`TopologyClosedEvent ` - Created when the topology is closed. - * - ``ServerHeartbeatStartedEvent`` - - Created when the heartbeat is started. + * - :php:`ServerHeartbeatStartedEvent ` + - Created when the server monitor sends a ``hello`` call to the server. + This action is called a heartbeat. - * - ``ServerHeartbeatSucceededEvent`` + * - :php:`ServerHeartbeatSucceededEvent ` - Created when the heartbeat succeeds. - * - ``ServerHeartbeatFailedEvent`` + * - :php:`ServerHeartbeatFailedEvent ` - Created when the heartbeat fails. +You can find a list of the monitoring subscriber classes and event +methods in the :php:`Monitoring classes and subscriber functions +` section of the PHP manual. + +Remove a Subscriber +------------------- + +Later in your application, you might not want to subscribe to +SDAM events. To unregister a subscriber from your client, use the +``MongoDB\Client::removeSubscriber()`` method. If you attempt to remove +a nonexistent subscriber, the method doesn't perform any action. + +The following code shows how to remove the subscriber that you +registered in the :ref:`php-subscribe-sdam` section: + +.. literalinclude:: /includes/monitoring/sdam.php + :start-after: start-remove-sub + :end-before: end-remove-sub + :language: php + :copyable: + :dedent: + API Documentation ----------------- @@ -127,7 +155,7 @@ To learn more about any of the classes or methods discussed in this guide, see t following API documentation: - :phpmethod:`MongoDB\Client::addSubscriber()` -- :phpclass:`MongoDB\Client` +- :phpmethod:`MongoDB\Client::removeSubscriber()` To learn more about subscriber classes and methods, see the following pages in the PHP manual: From 8cf4fc1bd31efd8d23ca33c9d0429f235fc01ad0 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 19 Sep 2024 13:43:46 -0400 Subject: [PATCH 076/149] single quotes --- source/includes/monitoring/sdam.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/includes/monitoring/sdam.php b/source/includes/monitoring/sdam.php index 8760ec5e..1647f9d9 100644 --- a/source/includes/monitoring/sdam.php +++ b/source/includes/monitoring/sdam.php @@ -1,6 +1,6 @@ stream, - "Server opening on %s:%s\n", + 'Server opening on %s:%s\n', $event->getHost(), $event->getPort(), ); @@ -42,7 +42,7 @@ public function topologyOpening(MongoDB\Driver\Monitoring\TopologyOpeningEvent $ $client->addSubscriber($subscriber); // end-add-sub -$collection->insertOne(["x" => 100]); +$collection->insertOne(['x' => 100]); // start-remove-sub $client->removeSubscriber($subscriber); From fc1506c33dda865b2d717ec090b112f57a3d9097 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 19 Sep 2024 13:48:39 -0400 Subject: [PATCH 077/149] links --- source/monitoring/cluster-monitoring.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt index 8c0aa8df..6a9dfcb1 100644 --- a/source/monitoring/cluster-monitoring.txt +++ b/source/monitoring/cluster-monitoring.txt @@ -95,40 +95,40 @@ documentation, and a description of when the event is published: * - Event Type - Description - * - :php:`ServerChangedEvent ` + * - :php:`ServerChangedEvent ` - Created when the server description changes, such as the server's type changing from secondary to primary. - * - :php:`ServerOpeningEvent ` + * - :php:`ServerOpeningEvent ` - Created when the server description is instantiated with its defaults. - * - :php:`ServerClosedEvent ` + * - :php:`ServerClosedEvent ` - Created when the server is closed. - * - :php:`TopologyChangedEvent ` + * - :php:`TopologyChangedEvent ` - Created when the topology description changes, such when there is an election of a new primary or disconnection of a ``mongos`` proxy. - * - :php:`TopologyOpeningEvent ` + * - :php:`TopologyOpeningEvent ` - Created when the topology description is initialized. - * - :php:`TopologyClosedEvent ` + * - :php:`TopologyClosedEvent ` - Created when the topology is closed. - * - :php:`ServerHeartbeatStartedEvent ` + * - :php:`ServerHeartbeatStartedEvent ` - Created when the server monitor sends a ``hello`` call to the server. This action is called a heartbeat. - * - :php:`ServerHeartbeatSucceededEvent ` + * - :php:`ServerHeartbeatSucceededEvent ` - Created when the heartbeat succeeds. - * - :php:`ServerHeartbeatFailedEvent ` + * - :php:`ServerHeartbeatFailedEvent ` - Created when the heartbeat fails. You can find a list of the monitoring subscriber classes and event methods in the :php:`Monitoring classes and subscriber functions -` section of the PHP manual. +` section of the PHP manual. Remove a Subscriber ------------------- From 25d4f88e8e8882627e3f1839f4b8ddaea742d55e Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 19 Sep 2024 13:50:56 -0400 Subject: [PATCH 078/149] vale --- .github/workflows/check-autobuilder.yml | 13 ------------- source/monitoring/cluster-monitoring.txt | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 .github/workflows/check-autobuilder.yml diff --git a/.github/workflows/check-autobuilder.yml b/.github/workflows/check-autobuilder.yml deleted file mode 100644 index 8495db96..00000000 --- a/.github/workflows/check-autobuilder.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Check Autobuilder for Errors - -on: - pull_request: - paths: - - "source/**" - -jobs: - check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: cbush/snooty-autobuilder-check@main diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt index 6a9dfcb1..5cdf97f5 100644 --- a/source/monitoring/cluster-monitoring.txt +++ b/source/monitoring/cluster-monitoring.txt @@ -55,7 +55,7 @@ server: .. note:: - As shown in the preceding code, you must implement all of the methods + As shown in the preceding code, you must implement all the methods of the ``SDAMSubscriber`` interface, even for events you are not subscribing to. The example defines the extra methods as empty so that the application does not output any messages for those events. From ae53fbbdd2a9cc7a4dfe6715630ab2cdbd5364bc Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 19 Sep 2024 15:43:41 -0400 Subject: [PATCH 079/149] remove older driver version past 1.15 --- .../language-compatibility-table-php.rst | 111 +---------- .../mongodb-compatibility-table-php.rst | 177 +----------------- 2 files changed, 3 insertions(+), 285 deletions(-) diff --git a/source/includes/language-compatibility-table-php.rst b/source/includes/language-compatibility-table-php.rst index c1d961f1..c50e52b3 100644 --- a/source/includes/language-compatibility-table-php.rst +++ b/source/includes/language-compatibility-table-php.rst @@ -39,120 +39,11 @@ - ✓ - ✓ - - * - ext + lib 1.15 [#PHP1.15-version-parity]_ + * - ext + lib 1.15 - - ✓ - ✓ - ✓ - ✓ - ✓ - - ✓ - - * - ext 1.14 + lib 1.13 - - - - - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.13 + lib 1.12 - - - - - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.12 + lib 1.11 - - - - - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.11 + lib 1.10 - - - - - - - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.10 + lib 1.9 - - - - - - - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.9 + lib 1.8 - - - - - - - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.8 + lib 1.7 - - - - - - - - - - ✓ - - ✓ - - ✓ - - * - ext 1.7 + lib 1.6 - - - - - - - - - - ✓ - - ✓ - - ✓ - - * - ext 1.6 + lib 1.5 - - - - - - - - - - ✓ - - ✓ - - ✓ - - * - ext 1.5 + lib 1.4 - - - - - - - - - - - - ✓ - - ✓ - - * - ext 1.4 + lib 1.3 - - - - - - - - - - - - - - ✓ - - * - ext 1.3 + lib 1.2 - - - - - - - - - - - - - ✓ \ No newline at end of file diff --git a/source/includes/mongodb-compatibility-table-php.rst b/source/includes/mongodb-compatibility-table-php.rst index 9900ded2..febec5a4 100644 --- a/source/includes/mongodb-compatibility-table-php.rst +++ b/source/includes/mongodb-compatibility-table-php.rst @@ -36,7 +36,7 @@ - ✓ - - * - ext + lib 1.15 [#PHP1.15-version-parity]_ + * - ext + lib 1.15 - ⊛ - ⊛ - ✓ @@ -45,177 +45,4 @@ - ✓ - ✓ - ✓ - - - - * - ext 1.14 + lib 1.13 - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - - - * - ext 1.13 + lib 1.12 - - ⊛ - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - - - * - ext 1.12 + lib 1.11 - - ⊛ - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.11 + lib 1.10 - - ⊛ - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.10 + lib 1.9 - - ⊛ - - ⊛ - - ⊛ - - ✓ [#PHPC1.10-PHPLIB1.9-driver-support]_ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.9 + lib 1.8 - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.8 + lib 1.7 - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.7 + lib 1.6 - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.6 + lib 1.5 - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - ✓ - - * - ext 1.5 + lib 1.4 - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ⊛ - - ✓ - - ✓ - - ✓ - - * - ext 1.4 + lib 1.3 - - - - - - - - - - - - - - - - ✓ - - ✓ - - * - ext 1.3 + lib 1.2 - - - - - - - - - - - - - - - - - - ✓ - - * - ext 1.2 + lib 1.1 - - - - - - - - - - - - - - - - - - ✓ - - * - ext 1.1 + lib 1.0 - - - - - - - - - - - - - - - - - - - - * - ext 1.0 - - - - - - - - - - - - - - - - - - - -.. [#PHP1.15-version-parity] Version 1.14 of the {+php-library+} has been - skipped to restore version parity between the library and extension. - -.. [#PHPC1.10-PHPLIB1.9-driver-support] The extension 1.10 + library 1.9 - driver does not support snapshot reads on secondaries. For more - information, see the - `MongoDB Server version 5.0 release notes `__. \ No newline at end of file + - \ No newline at end of file From 265476f8512c7c4da568f590e8231b149cbafa0a Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 19 Sep 2024 16:03:28 -0400 Subject: [PATCH 080/149] DOCSP-41991 What's New --- source/whats-new.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/source/whats-new.txt b/source/whats-new.txt index 420fd640..7cb4f9a9 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -32,4 +32,15 @@ What's New in 1.20 Support for MongoDB Server v3.6 is removed in this release of the library. -- Adds support for MongoDB Server v8.0. \ No newline at end of file +- Adds support for MongoDB Server v8.0. + +What's New in 1.18 +------------------ + +- Adds a new GridFS API to make it more convenient to work with files using PHP's + existing filesystem functions. The :ref:`MongoDB\GridFS\Bucket::registerGlobalStreamWrapperAlias() ` + method may be used to register a global alias for a GridFS bucket. After doing so, files within that bucket + can be accessed using only a file URI (e.g. "gridfs://mybucket/hello.txt"). A demonstration of this + API can be found in the `gridfs_stream_wrapper.php `_ + example script. + From 13ff9620f37fd3891bd208aa1927cdb473040861 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Fri, 20 Sep 2024 17:35:35 -0400 Subject: [PATCH 081/149] add rest of versions --- .../method/MongoDBClient-addSubscriber.txt | 2 + .../method/MongoDBClient-removeSubscriber.txt | 2 + ...ucket-registerGlobalStreamWrapperAlias.txt | 2 + source/whats-new.txt | 90 ++++++++++++++++++- 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/source/reference/method/MongoDBClient-addSubscriber.txt b/source/reference/method/MongoDBClient-addSubscriber.txt index 9a3344b0..5feb3b6e 100644 --- a/source/reference/method/MongoDBClient-addSubscriber.txt +++ b/source/reference/method/MongoDBClient-addSubscriber.txt @@ -1,3 +1,5 @@ +.. _api-client-add-subscriber: + ================================ MongoDB\\Client::addSubscriber() ================================ diff --git a/source/reference/method/MongoDBClient-removeSubscriber.txt b/source/reference/method/MongoDBClient-removeSubscriber.txt index e95f74e7..7fde784f 100644 --- a/source/reference/method/MongoDBClient-removeSubscriber.txt +++ b/source/reference/method/MongoDBClient-removeSubscriber.txt @@ -1,3 +1,5 @@ +.. _api-client-remove-subscriber: + =================================== MongoDB\\Client::removeSubscriber() =================================== diff --git a/source/reference/method/MongoDBGridFSBucket-registerGlobalStreamWrapperAlias.txt b/source/reference/method/MongoDBGridFSBucket-registerGlobalStreamWrapperAlias.txt index 405b0d3e..1bdaa409 100644 --- a/source/reference/method/MongoDBGridFSBucket-registerGlobalStreamWrapperAlias.txt +++ b/source/reference/method/MongoDBGridFSBucket-registerGlobalStreamWrapperAlias.txt @@ -1,3 +1,5 @@ +.. _api-gridfs-bucket-register-global: + =========================================================== MongoDB\\GridFS\\Bucket::registerGlobalStreamWrapperAlias() =========================================================== diff --git a/source/whats-new.txt b/source/whats-new.txt index 7cb4f9a9..77bf2d74 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -22,6 +22,14 @@ following versions of the {+php-library+}: * :ref:`Version 1.20 ` +* :ref:`Version 1.18 ` + +* :ref:`Version 1.17 ` + +* :ref:`Version 1.16 ` + +* :ref:`Version 1.15 ` + .. _php-lib-version-1.20: What's New in 1.20 @@ -34,13 +42,87 @@ What's New in 1.20 - Adds support for MongoDB Server v8.0. +.. _php-lib-version-1.18: + What's New in 1.18 ------------------ - Adds a new GridFS API to make it more convenient to work with files using PHP's - existing filesystem functions. The :ref:`MongoDB\GridFS\Bucket::registerGlobalStreamWrapperAlias() ` - method may be used to register a global alias for a GridFS bucket. After doing so, files within that bucket - can be accessed using only a file URI (e.g. "gridfs://mybucket/hello.txt"). A demonstration of this - API can be found in the `gridfs_stream_wrapper.php `_ + existing filesystem functions. The :ref:`MongoDB\GridFS\Bucket::registerGlobalStreamWrapperAlias() ` + method may be used to register a global alias for a GridFS bucket. After + doing so, files within that bucket can be accessed using only a file URI + (e.g. "gridfs://mybucket/hello.txt"). A demonstration of this API can be found + in the `gridfs_stream_wrapper.php `_ example script. +- The ``MongoDB\Client`` class now has :ref:`addSubscriber() ` + and :ref:`removeSubscriber()` methods to make it + easier to register monitoring classes on the underlying ``MongoDB\Driver\Manager`` + object. + +To learn more about this release, see the `v1.18 Release Notes +`__ on GitHub. + +.. _php-lib-version-1.17: + +What's New in 1.17 +------------------ + +- Introduces a new "codec" API for converting BSON to and from PHP objects. + More information on this feature may be found in the + :ref:`Codecs tutorial `. + +- Adds :ref:`MongoDB\add_logger() ` and + :ref:`MongoDB\remove_logger() ` functions to the library. + These functions allow applications to register a `PSR-3 Logger `__ + to receive log messages emitted by the driver. Previously, logs were only + accessible via the extension's `mongodb.debug `__ + INI setting. + +- Introduces new :ref:`MongoDB\Collection ` methods + to create and manage :atlas:`Atlas Search indexes `. Atlas + Search indexes can be queried using the :manual:`$search ` + aggregation pipeline stage, which is supported in all versions of the library. + +- Upgrades the ``mongodb`` extension requirement to 1.17.0. Support for PHP + 7.2 and 7.3 has been removed and the library now requires PHP 7.4 or newer. + +To learn more about this release, see the `v1.17 Release Notes +`__ on GitHub. + +.. _php-lib-version-1.16: + +What's New in 1.16 +------------------ + +- Introduces support for :v7.0:`MongoDB 7.0 `. + +- Introduces :ref:`MongoDB\Database::createEncryptedCollection() `. + This method automatically creates data encryption keys when creating a new + encrypted collection. + +- This release upgrades the ``mongodb`` extension requirement to 1.16.0. + +To learn more about this release, see the `v1.16 Release Notes +`__ on GitHub. + +.. _php-lib-version-1.15: + +What's New in 1.15 +------------------ + +- Adds new ``examples/`` and ``tools/`` directories to library repository, + which contain code snippets and scripts that may prove useful when writing + or debugging applications, respectively. These directories are intended to + supplement the library's existing documentation, and will be added to over time. + +- Various backwards compatible typing improvements have been made throughout the + library. Downstream impact for these changes are discussed in + `UPGRADE-1.15.md `__. + +- Integrates `Psalm `__ for static analysis. + +- This release upgrades the ``mongodb`` extension requirement to 1.15.0. + +To learn more about this release, see the `v1.15 Release Notes +`__ on GitHub. From 99c571d432de8f9e4459c8feea246570ddd4df52 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Fri, 20 Sep 2024 17:54:57 -0400 Subject: [PATCH 082/149] fix links --- source/reference/function/add_logger.txt | 2 ++ source/reference/function/remove_logger.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/source/reference/function/add_logger.txt b/source/reference/function/add_logger.txt index 69076915..b1c3046c 100644 --- a/source/reference/function/add_logger.txt +++ b/source/reference/function/add_logger.txt @@ -1,3 +1,5 @@ +.. _api-add-logger: + ===================== MongoDB\\add_logger() ===================== diff --git a/source/reference/function/remove_logger.txt b/source/reference/function/remove_logger.txt index 369c5c13..41162dde 100644 --- a/source/reference/function/remove_logger.txt +++ b/source/reference/function/remove_logger.txt @@ -1,3 +1,5 @@ +.. _api-remove-logger: + ======================== MongoDB\\remove_logger() ======================== From de61ae17c297cad270884875881788d418d11882 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Fri, 20 Sep 2024 17:57:52 -0400 Subject: [PATCH 083/149] fix links --- source/reference/class/MongoDBCollection.txt | 2 ++ .../MongoDBDatabase-createEncryptedCollection.txt | 2 ++ source/whats-new.txt | 10 +++++----- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/source/reference/class/MongoDBCollection.txt b/source/reference/class/MongoDBCollection.txt index 462ac4d9..b734755e 100644 --- a/source/reference/class/MongoDBCollection.txt +++ b/source/reference/class/MongoDBCollection.txt @@ -1,3 +1,5 @@ +.. _api-mongodb-collection-class: + ========================= MongoDB\\Collection Class ========================= diff --git a/source/reference/method/MongoDBDatabase-createEncryptedCollection.txt b/source/reference/method/MongoDBDatabase-createEncryptedCollection.txt index e6a266fb..9ee39aef 100644 --- a/source/reference/method/MongoDBDatabase-createEncryptedCollection.txt +++ b/source/reference/method/MongoDBDatabase-createEncryptedCollection.txt @@ -1,3 +1,5 @@ +.. _api-database-create-encrypted: + ============================================== MongoDB\\Database::createEncryptedCollection() ============================================== diff --git a/source/whats-new.txt b/source/whats-new.txt index 77bf2d74..9b4e026d 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -52,13 +52,13 @@ What's New in 1.18 method may be used to register a global alias for a GridFS bucket. After doing so, files within that bucket can be accessed using only a file URI (e.g. "gridfs://mybucket/hello.txt"). A demonstration of this API can be found - in the `gridfs_stream_wrapper.php `_ + in the `gridfs_stream_wrapper.php `__ example script. -- The ``MongoDB\Client`` class now has :ref:`addSubscriber() ` - and :ref:`removeSubscriber()` methods to make it - easier to register monitoring classes on the underlying ``MongoDB\Driver\Manager`` - object. +- Adds :ref:`addSubscriber() ` and + :ref:`removeSubscriber()` methods to the + ``MongoDB\Client`` class to make it easier to register monitoring classes + on the underlying ``MongoDB\Driver\Manager`` object. To learn more about this release, see the `v1.18 Release Notes `__ on GitHub. From e3351c5410ce6637f60a92652272d2a212e51831 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 23 Sep 2024 10:23:24 -0400 Subject: [PATCH 084/149] JM tech review 2 --- source/monitoring/cluster-monitoring.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt index 5cdf97f5..44bb4370 100644 --- a/source/monitoring/cluster-monitoring.txt +++ b/source/monitoring/cluster-monitoring.txt @@ -22,9 +22,9 @@ Overview This guide shows you how to use the {+php-library+} to monitor server discovery and monitoring (SDAM) events in a MongoDB instance, replica -set, or sharded cluster. These events occur when there -are any changes in the state of the MongoDB instance or cluster that you -are connected to. +set, or sharded cluster. These events occur when there are any changes +in the state of the MongoDB instance or cluster that you are connected +to. You might use information about SDAM events in your application to understand cluster changes, assess cluster health, or perform capacity @@ -100,21 +100,20 @@ documentation, and a description of when the event is published: changing from secondary to primary. * - :php:`ServerOpeningEvent ` - - Created when the server description is instantiated with its - defaults. + - Created when a server connection is established. * - :php:`ServerClosedEvent ` - - Created when the server is closed. + - Created when a server connection is closed. * - :php:`TopologyChangedEvent ` - Created when the topology description changes, such when there is - an election of a new primary or disconnection of a ``mongos`` proxy. + an election of a new primary. * - :php:`TopologyOpeningEvent ` - - Created when the topology description is initialized. + - Created when the driver first connects to the cluster. * - :php:`TopologyClosedEvent ` - - Created when the topology is closed. + - Created when the driver disconnects from the cluster. * - :php:`ServerHeartbeatStartedEvent ` - Created when the server monitor sends a ``hello`` call to the server. From 5812fdf16c69fb07dc4e7eb7ed7dc1f049442243 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Mon, 23 Sep 2024 12:16:26 -0400 Subject: [PATCH 085/149] DOCSP-41964: Time series collections (#138) * DOCSP-41964: Time series collections * toc * edits * keywords * SA feedback * JT feedback --- source/databases-collections.txt | 8 +- source/databases-collections/time-series.txt | 213 ++++++++++++++++++ .../databases-collections/time-series.php | 48 ++++ source/tutorial/crud.txt | 2 - 4 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 source/databases-collections/time-series.txt create mode 100644 source/includes/databases-collections/time-series.php diff --git a/source/databases-collections.txt b/source/databases-collections.txt index 1a650dc9..f031a006 100644 --- a/source/databases-collections.txt +++ b/source/databases-collections.txt @@ -17,6 +17,12 @@ Databases and Collections .. meta:: :keywords: table, row, organize, storage, code example +.. toctree:: + :titlesonly: + :maxdepth: 1 + + /databases-collections/time-series + Overview -------- @@ -319,4 +325,4 @@ guide, see the following API documentation: - :phpmethod:`MongoDB\Database::selectCollection()` - :phpmethod:`MongoDB\Database::createCollection()` - :phpmethod:`MongoDB\Database::listCollections()` -- :phpmethod:`MongoDB\Database::dropCollection()` \ No newline at end of file +- :phpmethod:`MongoDB\Database::dropCollection()` diff --git a/source/databases-collections/time-series.txt b/source/databases-collections/time-series.txt new file mode 100644 index 00000000..9c21e2e3 --- /dev/null +++ b/source/databases-collections/time-series.txt @@ -0,0 +1,213 @@ +.. _php-time-series: + +======================= +Time Series Collections +======================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: chronological, data format, code example + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} to create +and interact with **time series collections**. These collections store +time series data, which is composed of the following components: + +- Measured quantity +- Timestamp for the measurement +- Metadata that describes the measurement + +The following table describes sample situations for which you can store time +series data: + +.. list-table:: + :widths: 33, 33, 33 + :header-rows: 1 + :stub-columns: 1 + + * - Situation + - Measured Quantity + - Metadata + + * - Recording monthly sales by industry + - Revenue in USD + - Company, country + + * - Tracking weather changes + - Precipitation level + - Location, sensor type + + * - Recording fluctuations in housing prices + - Monthly rent price + - Location, currency + +.. _php-time-series-create: + +Create a Time Series Collection +------------------------------- + +.. important:: Server Version for Time Series Collections + + To create and interact with time series collections, you must be + connected to a deployment running {+mdb-server+} 5.0 or later. + +You can create a time series collection to store time series data. +To create a time series collection, pass an options array to the +``MongoDB\Database::createCollection()`` method that sets the +``timeseries`` option. When setting this option, include the following fields: + +- ``timeField``: Specifies the field that stores a timestamp in each time series document. +- ``metaField``: Specifies the field that stores metadata in each time series document. +- ``granularity``: Specifies the approximate time between consecutive timestamps. The possible + values are ``'seconds'``, ``'minutes'``, and ``'hours'``. + +.. _php-time-series-create-example: + +Example +~~~~~~~ + +This example creates the ``sept2023`` time series collection in the +``precipitation`` database with the following configuration: + +- ``timeField`` is set to ``'timestamp'`` +- ``metaField`` is set to ``'location'`` +- ``granularity`` is set to ``'minutes'`` + +.. literalinclude:: /includes/databases-collections/time-series.php + :start-after: start-create-ts + :end-before: end-create-ts + :language: php + :dedent: + +To verify that you successfully created the time series collection, call +the ``MongoDB\Database::listCollections()`` method on the database and +print the results: + +.. io-code-block:: + :copyable: + + .. input:: /includes/databases-collections/time-series.php + :start-after: start-list-colls + :end-before: end-list-colls + :language: php + :dedent: + + .. output:: + :language: console + :visible: false + + MongoDB\Model\CollectionInfo Object + ( + [name] => sept2023 + [type] => timeseries + [options] => Array + ( + … + ) + + [info] => Array + ( + … + ) + ) + MongoDB\Model\CollectionInfo Object + ( + [name] => system.buckets.sept2023 + [type] => collection + [options] => Array + ( + … + ) + + [info] => Array + ( + … + ) + ) + +.. note:: + + MongoDB stores system data associated with time series collections + in the ``.system.buckets`` namespace. For more information, + see :manual:`database.system.buckets ` + in the {+mdb-server+} manual. + +.. _php-time-series-insert: + +Insert Time Series Data +----------------------- + +You can insert data into a time series collection by using the ``MongoDB\Collection::insertOne()`` +or ``MongoDB\Collection::insertMany()`` methods and specifying the measurement, +timestamp, and metadata in each inserted document. + +.. tip:: + + To learn more about inserting documents into a collection, see the :ref:`php-write-insert` + guide. + +Example +~~~~~~~ + +This example inserts New York City precipitation data into the ``sept2023`` +time series collection created in the :ref:`Create a Time Series Collection example +`. Each document contains the following fields: + +- ``precipitation_mm``, which stores precipitation measurements in millimeters +- ``location``, which stores location metadata +- ``timestamp``, which stores the time of the measurement collection + +.. literalinclude:: /includes/databases-collections/time-series.php + :start-after: start-insert-ts + :end-before: end-insert-ts + :language: php + :dedent: + +.. _php-time-series-query: + +Query Time Series Collections +----------------------------- + +You can use the same syntax and conventions to query data stored in a time +series collection as you use when performing read or aggregation operations on +other collections. To find more information about these operations, see +the :ref:`Additional Information ` section. + +.. _php-time-series-addtl-info: + +Additional Information +---------------------- + +To learn more about the concepts mentioned in this guide, see the +following Server manual entries: + +- :manual:`Time Series ` +- :manual:`Create and Query a Time Series Collection ` +- :manual:`Set Granularity for Time Series Data ` + +To learn more about performing read operations, see :ref:`php-read`. + +To learn more about performing aggregation operations, see the :ref:`php-aggregation` +guide. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about the methods mentioned in this guide, see the following +API documentation: + +- :phpmethod:`MongoDB\Database::createCollection()` +- :phpmethod:`MongoDB\Database::listCollections()` +- :phpmethod:`MongoDB\Collection::insertOne()` +- :phpmethod:`MongoDB\Collection::insertMany()` diff --git a/source/includes/databases-collections/time-series.php b/source/includes/databases-collections/time-series.php new file mode 100644 index 00000000..35b005e2 --- /dev/null +++ b/source/includes/databases-collections/time-series.php @@ -0,0 +1,48 @@ +precipitation; + +$options = [ + 'timeseries' => [ + 'timeField' => 'timestamp', + 'metaField' => 'location', + 'granularity' => 'minutes', + ] +]; + +$collection = $db->createCollection('sept2023', $options); +// end-create-ts + +// Lists the collections in the "precipitation" database +// start-list-colls +$cursor = $db->listCollections(); + +foreach ($cursor as $collectionInfo) { + print_r($collectionInfo) . PHP_EOL; +} +// end-list-colls + +// Inserts precipitation time series data about New York City into the collection +// start-insert-ts +$collection = $db->sept2023; +$result = $collection->insertMany( + [ + [ + 'precipitation_mm' => 0.5, + 'location' => 'New York City', + 'timestamp' => new MongoDB\BSON\UTCDateTime(1694829060000), + ], + [ + 'precipitation_mm' => 2.8, + 'location' => 'New York City', + 'timestamp' => new MongoDB\BSON\UTCDateTime(1695594780000), + ], + ] +); +// end-insert-ts diff --git a/source/tutorial/crud.txt b/source/tutorial/crud.txt index a69ec662..036e176f 100644 --- a/source/tutorial/crud.txt +++ b/source/tutorial/crud.txt @@ -414,8 +414,6 @@ following example finds restaurants whose name starts with "(Library)": 'name' => new MongoDB\BSON\Regex('^' . preg_quote('(Library)')), ]); -.. _php-aggregation: - Complex Queries with Aggregation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 4a39d20eb4e85f240b10c03d5ccedb6d0c38dc59 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 23 Sep 2024 15:39:25 -0400 Subject: [PATCH 086/149] JM final fixes --- source/monitoring/cluster-monitoring.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt index 44bb4370..d9d9901e 100644 --- a/source/monitoring/cluster-monitoring.txt +++ b/source/monitoring/cluster-monitoring.txt @@ -96,8 +96,8 @@ documentation, and a description of when the event is published: - Description * - :php:`ServerChangedEvent ` - - Created when the server description changes, such as the server's type - changing from secondary to primary. + - Created when the server description changes, such as the server's + type changing from secondary to primary. * - :php:`ServerOpeningEvent ` - Created when a server connection is established. @@ -106,8 +106,8 @@ documentation, and a description of when the event is published: - Created when a server connection is closed. * - :php:`TopologyChangedEvent ` - - Created when the topology description changes, such when there is - an election of a new primary. + - Created when the topology description changes, such as when there + is an election of a new primary. * - :php:`TopologyOpeningEvent ` - Created when the driver first connects to the cluster. @@ -116,7 +116,7 @@ documentation, and a description of when the event is published: - Created when the driver disconnects from the cluster. * - :php:`ServerHeartbeatStartedEvent ` - - Created when the server monitor sends a ``hello`` call to the server. + - Created when the server monitor sends a ``hello`` command to the server. This action is called a heartbeat. * - :php:`ServerHeartbeatSucceededEvent ` From 122f58f580e6f7bf402b7a0f20ec7bf9735b3f51 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Mon, 23 Sep 2024 15:51:46 -0400 Subject: [PATCH 087/149] review comments --- source/reference/class/MongoDBCollection.txt | 2 - source/reference/function/add_logger.txt | 2 - source/reference/function/remove_logger.txt | 2 - .../method/MongoDBClient-addSubscriber.txt | 2 - .../method/MongoDBClient-removeSubscriber.txt | 2 - ...goDBDatabase-createEncryptedCollection.txt | 2 - ...ucket-registerGlobalStreamWrapperAlias.txt | 2 - source/whats-new.txt | 37 ++++++++++--------- 8 files changed, 20 insertions(+), 31 deletions(-) diff --git a/source/reference/class/MongoDBCollection.txt b/source/reference/class/MongoDBCollection.txt index b734755e..462ac4d9 100644 --- a/source/reference/class/MongoDBCollection.txt +++ b/source/reference/class/MongoDBCollection.txt @@ -1,5 +1,3 @@ -.. _api-mongodb-collection-class: - ========================= MongoDB\\Collection Class ========================= diff --git a/source/reference/function/add_logger.txt b/source/reference/function/add_logger.txt index b1c3046c..69076915 100644 --- a/source/reference/function/add_logger.txt +++ b/source/reference/function/add_logger.txt @@ -1,5 +1,3 @@ -.. _api-add-logger: - ===================== MongoDB\\add_logger() ===================== diff --git a/source/reference/function/remove_logger.txt b/source/reference/function/remove_logger.txt index 41162dde..369c5c13 100644 --- a/source/reference/function/remove_logger.txt +++ b/source/reference/function/remove_logger.txt @@ -1,5 +1,3 @@ -.. _api-remove-logger: - ======================== MongoDB\\remove_logger() ======================== diff --git a/source/reference/method/MongoDBClient-addSubscriber.txt b/source/reference/method/MongoDBClient-addSubscriber.txt index 5feb3b6e..9a3344b0 100644 --- a/source/reference/method/MongoDBClient-addSubscriber.txt +++ b/source/reference/method/MongoDBClient-addSubscriber.txt @@ -1,5 +1,3 @@ -.. _api-client-add-subscriber: - ================================ MongoDB\\Client::addSubscriber() ================================ diff --git a/source/reference/method/MongoDBClient-removeSubscriber.txt b/source/reference/method/MongoDBClient-removeSubscriber.txt index 7fde784f..e95f74e7 100644 --- a/source/reference/method/MongoDBClient-removeSubscriber.txt +++ b/source/reference/method/MongoDBClient-removeSubscriber.txt @@ -1,5 +1,3 @@ -.. _api-client-remove-subscriber: - =================================== MongoDB\\Client::removeSubscriber() =================================== diff --git a/source/reference/method/MongoDBDatabase-createEncryptedCollection.txt b/source/reference/method/MongoDBDatabase-createEncryptedCollection.txt index 9ee39aef..e6a266fb 100644 --- a/source/reference/method/MongoDBDatabase-createEncryptedCollection.txt +++ b/source/reference/method/MongoDBDatabase-createEncryptedCollection.txt @@ -1,5 +1,3 @@ -.. _api-database-create-encrypted: - ============================================== MongoDB\\Database::createEncryptedCollection() ============================================== diff --git a/source/reference/method/MongoDBGridFSBucket-registerGlobalStreamWrapperAlias.txt b/source/reference/method/MongoDBGridFSBucket-registerGlobalStreamWrapperAlias.txt index 1bdaa409..405b0d3e 100644 --- a/source/reference/method/MongoDBGridFSBucket-registerGlobalStreamWrapperAlias.txt +++ b/source/reference/method/MongoDBGridFSBucket-registerGlobalStreamWrapperAlias.txt @@ -1,5 +1,3 @@ -.. _api-gridfs-bucket-register-global: - =========================================================== MongoDB\\GridFS\\Bucket::registerGlobalStreamWrapperAlias() =========================================================== diff --git a/source/whats-new.txt b/source/whats-new.txt index 9b4e026d..96bb4fb5 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -35,12 +35,12 @@ following versions of the {+php-library+}: What's New in 1.20 ------------------ -.. important:: MongoDB Server v3.6 End-of-Life +.. important:: {+mdb-server+} v3.6 End-of-Life - Support for MongoDB Server v3.6 is removed in this release of the + Support for {+mdb-server+} v3.6 is removed in this release of the library. -- Adds support for MongoDB Server v8.0. +- Adds support for {+mdb-server+} v8.0. .. _php-lib-version-1.18: @@ -48,15 +48,15 @@ What's New in 1.18 ------------------ - Adds a new GridFS API to make it more convenient to work with files using PHP's - existing filesystem functions. The :ref:`MongoDB\GridFS\Bucket::registerGlobalStreamWrapperAlias() ` + existing filesystem functions. The :phpmethod:`MongoDB\GridFS\Bucket::registerGlobalStreamWrapperAlias()` method may be used to register a global alias for a GridFS bucket. After - doing so, files within that bucket can be accessed using only a file URI + doing so, files within that bucket can be accessed by using only a file URI (e.g. "gridfs://mybucket/hello.txt"). A demonstration of this API can be found in the `gridfs_stream_wrapper.php `__ example script. -- Adds :ref:`addSubscriber() ` and - :ref:`removeSubscriber()` methods to the +- Adds :phpmethod:`MongoDB\Client::addSubscriber()` and + :phpmethod:`MongoDB\Client::removeSubscriber()` methods to the ``MongoDB\Client`` class to make it easier to register monitoring classes on the underlying ``MongoDB\Driver\Manager`` object. @@ -72,17 +72,20 @@ What's New in 1.17 More information on this feature may be found in the :ref:`Codecs tutorial `. -- Adds :ref:`MongoDB\add_logger() ` and - :ref:`MongoDB\remove_logger() ` functions to the library. +- Adds :phpmethod:`MongoDB\add_logger()` and + :phpmethod:`MongoDB\remove_logger()` functions to the library. These functions allow applications to register a `PSR-3 Logger `__ to receive log messages emitted by the driver. Previously, logs were only accessible via the extension's `mongodb.debug `__ INI setting. -- Introduces new :ref:`MongoDB\Collection ` methods - to create and manage :atlas:`Atlas Search indexes `. Atlas - Search indexes can be queried using the :manual:`$search ` +- Introduces new :phpclass:`MongoDB\Collection` methods to create and manage + Atlas Search indexes. Atlas Search indexes can be queried using the ``$search`` aggregation pipeline stage, which is supported in all versions of the library. + To learn more about Atlas Search indexes and the specfics of the ``$search`` + aggregation stage, see the :atlas:`Atlas Search indexes ` + documentation and :manual:`$search `, + respectively. - Upgrades the ``mongodb`` extension requirement to 1.17.0. Support for PHP 7.2 and 7.3 has been removed and the library now requires PHP 7.4 or newer. @@ -97,7 +100,7 @@ What's New in 1.16 - Introduces support for :v7.0:`MongoDB 7.0 `. -- Introduces :ref:`MongoDB\Database::createEncryptedCollection() `. +- Introduces :phpmethod:`MongoDB\Database::createEncryptedCollection()`. This method automatically creates data encryption keys when creating a new encrypted collection. @@ -111,18 +114,18 @@ To learn more about this release, see the `v1.16 Release Notes What's New in 1.15 ------------------ -- Adds new ``examples/`` and ``tools/`` directories to library repository, +- Adds new ``examples/`` and ``tools/`` directories to the library repository, which contain code snippets and scripts that may prove useful when writing or debugging applications, respectively. These directories are intended to - supplement the library's existing documentation, and will be added to over time. + supplement the library's existing documentation and will be added to over time. -- Various backwards compatible typing improvements have been made throughout the +- Adds various backwards compatible typing improvements throughout the library. Downstream impact for these changes are discussed in `UPGRADE-1.15.md `__. - Integrates `Psalm `__ for static analysis. -- This release upgrades the ``mongodb`` extension requirement to 1.15.0. +- Upgrades the ``mongodb`` extension requirement to 1.15.0. To learn more about this release, see the `v1.15 Release Notes `__ on GitHub. From c4b9611f6d7bb0f916b7fbc41a8ff2993969c833 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Mon, 23 Sep 2024 15:59:20 -0400 Subject: [PATCH 088/149] typo --- source/whats-new.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/whats-new.txt b/source/whats-new.txt index 96bb4fb5..446174f7 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -82,7 +82,7 @@ What's New in 1.17 - Introduces new :phpclass:`MongoDB\Collection` methods to create and manage Atlas Search indexes. Atlas Search indexes can be queried using the ``$search`` aggregation pipeline stage, which is supported in all versions of the library. - To learn more about Atlas Search indexes and the specfics of the ``$search`` + To learn more about Atlas Search indexes and the specifics of the ``$search`` aggregation stage, see the :atlas:`Atlas Search indexes ` documentation and :manual:`$search `, respectively. From a5f2990d863a997a1c5179b979b32d94043c0938 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Mon, 23 Sep 2024 18:57:22 -0400 Subject: [PATCH 089/149] DOCSP-41973 Read Landing Page --- source/read.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/source/read.txt b/source/read.txt index 0b6f6c78..bfcbb1a0 100644 --- a/source/read.txt +++ b/source/read.txt @@ -16,3 +16,25 @@ Read Data from MongoDB /read/specify-a-query /read/distinct /read/change-streams + +Overview +-------- + +On this page, you can see copyable code examples that show common +{+driver-short+} methods for retrieving documents. + +.. tip:: + + To learn more about any of the methods shown on this page, see the link + provided in each section. + +To use an example from this page, copy the code example into the +:ref:`sample application ` or your own application. +Be sure to replace all placeholders, such as ````, with +the relevant values for your MongoDB deployment. + +.. _php-read-sample: + + + + From 83aa662c2ab876f96e523e5ab3acb15251ea8dcd Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Mon, 23 Sep 2024 19:01:31 -0400 Subject: [PATCH 090/149] review comments --- source/whats-new.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/whats-new.txt b/source/whats-new.txt index 446174f7..7d39f5e7 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -58,7 +58,7 @@ What's New in 1.18 - Adds :phpmethod:`MongoDB\Client::addSubscriber()` and :phpmethod:`MongoDB\Client::removeSubscriber()` methods to the ``MongoDB\Client`` class to make it easier to register monitoring classes - on the underlying ``MongoDB\Driver\Manager`` object. + scoped to the underlying ``MongoDB\Driver\Manager`` object. To learn more about this release, see the `v1.18 Release Notes `__ on GitHub. @@ -104,7 +104,7 @@ What's New in 1.16 This method automatically creates data encryption keys when creating a new encrypted collection. -- This release upgrades the ``mongodb`` extension requirement to 1.16.0. +- Upgrades the ``mongodb`` extension requirement to 1.16.0. To learn more about this release, see the `v1.16 Release Notes `__ on GitHub. From f3de45a4974a7b68a6dd432a69e8283e49cb7db7 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Tue, 24 Sep 2024 13:51:45 -0400 Subject: [PATCH 091/149] vale errors --- source/whats-new.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source/whats-new.txt b/source/whats-new.txt index 7d39f5e7..d0925c32 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -76,7 +76,7 @@ What's New in 1.17 :phpmethod:`MongoDB\remove_logger()` functions to the library. These functions allow applications to register a `PSR-3 Logger `__ to receive log messages emitted by the driver. Previously, logs were only - accessible via the extension's `mongodb.debug `__ + available through the extension's `mongodb.debug `__ INI setting. - Introduces new :phpclass:`MongoDB\Collection` methods to create and manage @@ -84,8 +84,7 @@ What's New in 1.17 aggregation pipeline stage, which is supported in all versions of the library. To learn more about Atlas Search indexes and the specifics of the ``$search`` aggregation stage, see the :atlas:`Atlas Search indexes ` - documentation and :manual:`$search `, - respectively. + documentation and :manual:`$search `. - Upgrades the ``mongodb`` extension requirement to 1.17.0. Support for PHP 7.2 and 7.3 has been removed and the library now requires PHP 7.4 or newer. @@ -116,7 +115,7 @@ What's New in 1.15 - Adds new ``examples/`` and ``tools/`` directories to the library repository, which contain code snippets and scripts that may prove useful when writing - or debugging applications, respectively. These directories are intended to + or debugging applications. These directories are intended to supplement the library's existing documentation and will be added to over time. - Adds various backwards compatible typing improvements throughout the From d6803c437df61540ab2500529d03332529ff90f5 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Tue, 24 Sep 2024 13:55:23 -0400 Subject: [PATCH 092/149] small thing --- source/whats-new.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/whats-new.txt b/source/whats-new.txt index d0925c32..49bc54c3 100644 --- a/source/whats-new.txt +++ b/source/whats-new.txt @@ -77,7 +77,7 @@ What's New in 1.17 These functions allow applications to register a `PSR-3 Logger `__ to receive log messages emitted by the driver. Previously, logs were only available through the extension's `mongodb.debug `__ - INI setting. + ``INI`` setting. - Introduces new :phpclass:`MongoDB\Collection` methods to create and manage Atlas Search indexes. Atlas Search indexes can be queried using the ``$search`` From f11a3024d648ccf4a222b066e2bfc6e22cd933aa Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Tue, 24 Sep 2024 18:38:55 -0400 Subject: [PATCH 093/149] full page with ex --- .../usage-examples/read-code-examples.php | 67 ++++++++++ source/read.txt | 115 ++++++++++++++++++ source/read/retrieve.txt | 2 +- 3 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 source/includes/usage-examples/read-code-examples.php diff --git a/source/includes/usage-examples/read-code-examples.php b/source/includes/usage-examples/read-code-examples.php new file mode 100644 index 00000000..8b73bc15 --- /dev/null +++ b/source/includes/usage-examples/read-code-examples.php @@ -0,0 +1,67 @@ +sample_mflix->movies; + +// Find One +// start-find-one +$document = $collection->findOne(['year' => 1994]); +echo json_encode($document) , "\n"; +// end-find-one + +// Find Multiple +// start-find-multiple +$resultsMultiple = $collection->find(['year' => 1970]); +foreach ($resultsMultiple as $doc) { + echo json_encode($doc) , "\n"; +} +// end-find-multiple + +// Count Document +// start-count +$result = $collection->countDocuments([]); +echo "Number of documents: " . $result; +// end-count + +// Count Specific Documents +// start-count-specific +$result = $collection->countDocuments(['year' => 2010]); +echo "Number of companies founded in 2010: " . $result; +// end-count-specific + +// Estimated Count +// start-count-estimate +$result = $collection->estimatedDocumentCount(); +echo "Estimated number of documents: " . $result; +// end-count-estimate + +// Distinct Values +// start-distinct +$results = $collection->distinct('year', []); +foreach ($results as $value) { + echo json_encode($value) . PHP_EOL; +} +// end-distinct + +// Data Changes +// start-change-stream +$changeStream = $collection->watch(); + +for ($changeStream->rewind(); true; $changeStream->next()) { + if ( ! $changeStream->valid()) { + continue; + } + $event = $changeStream->current(); + echo toJSON($event) . PHP_EOL; + + if ($event['operationType'] === 'invalidate') { + break; + } +} +// end-change-stream \ No newline at end of file diff --git a/source/read.txt b/source/read.txt index bfcbb1a0..c380d508 100644 --- a/source/read.txt +++ b/source/read.txt @@ -4,6 +4,12 @@ Read Data from MongoDB ====================== +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + .. toctree:: :titlesonly: :maxdepth: 1 @@ -35,6 +41,115 @@ the relevant values for your MongoDB deployment. .. _php-read-sample: +.. include:: /includes/usage-examples/sample-app-intro.rst + +.. literalinclude:: /includes/usage-examples/sample-app.php + :language: php + :dedent: + :linenos: + :emphasize-lines: 10-12 + +Find One +-------- + +The following code shows how to retrieve a single document from a collection +that matches the specified criteria: + +.. literalinclude:: /includes/usage-examples/read-code-examples.php + :start-after: start-find-one + :end-before: end-find-one + :language: php + :dedent: + +To learn more about the ``findOne()`` method, see the :ref:`php-retrieve-find-one` +section in the Retrieve Data guide. + +Find Multiple +------------- + +The following code shows how to retrieve all documents from a collection +that match the specified criteria: + +.. literalinclude:: /includes/usage-examples/read-code-examples.php + :start-after: start-find-multiple + :end-before: end-find-multiple + :language: php + :dedent: + +To learn more about the ``find()`` method, see the :ref:`php-retrieve-find-multiple` +section in the Retrieve Data guide. + +Count Documents in a Collection +------------------------------- + +The following code shows how to count the number of documents in +a collection: + +.. literalinclude:: /includes/usage-examples/read-code-examples.php + :start-after: start-count + :end-before: end-count + :language: php + :dedent: + +To learn more about the ``countDocuments()`` method, see the +:ref:`php-accurate-count` section in the Count Documents guide. + +Count Documents Returned from a Query +------------------------------------- + +The following code shows how to count documents in a collection +that match the specified criteria: + +.. literalinclude:: /includes/usage-examples/read-code-examples.php + :start-after: start-count-specific + :end-before: end-count-specific + :language: php + :dedent: + +To learn more about the ``countDocuments()`` method, see the +:ref:`php-accurate-count` section in the Count Documents guide. + +Estimated Document Count +------------------------ + +The following code shows how to retrieve an estimated count of the +number of documents in a collection: + +.. literalinclude:: /includes/usage-examples/read-code-examples.php + :start-after: start-count-estimate + :end-before: end-count-estimate + :language: php + :dedent: + +To learn more about the ``estimatedDocumentCount()`` method, see the +:ref:`php-estimated-count` section in the Count Documents guide. + +Retrieve Distinct Values +------------------------ + +The following code shows how to retrieve the unique values of a field +for documents that match the specified criteria: + +.. literalinclude:: /includes/usage-examples/read-code-examples.php + :start-after: start-distinct + :end-before: end-distinct + :language: php + :dedent: + +To learn more about the ``distinct()`` method, see the +:ref:`php-distinct` guide. + +Monitor Data Changes +-------------------- +The following code shows how to monitor and print changes to a +collection: +.. literalinclude:: /includes/usage-examples/read-code-examples.php + :start-after: start-change-stream + :end-before: end-change-stream + :language: php + :dedent: +To learn more about the ``watch()`` method, see the +:ref:`php-change-streams` guide. diff --git a/source/read/retrieve.txt b/source/read/retrieve.txt index cd1507db..283c29aa 100644 --- a/source/read/retrieve.txt +++ b/source/read/retrieve.txt @@ -52,7 +52,7 @@ The {+php-library+} includes two methods for retrieving documents from a collect take a **query filter** and return one or more matching documents. A query filter specifies the search criteria that the driver uses to retrieve documents in your query. -.. TODO: To learn more about query filters, see :ref:`php-specify-query`. +To learn more about query filters, see :ref:`php-specify-query`. .. _php-retrieve-find-one: From fc6dfda1655b4c74862595fb76d3667270541fc6 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Tue, 24 Sep 2024 18:44:26 -0400 Subject: [PATCH 094/149] add page --- snooty.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/snooty.toml b/snooty.toml index 938cdc0d..248b1c64 100644 --- a/snooty.toml +++ b/snooty.toml @@ -22,6 +22,7 @@ toc_landing_pages = [ "/reference/class/MongoDBModelDatabaseInfo", "/reference/class/MongoDBModelIndexInfo", "/get-started", + "/read", "/write", "/indexes" ] From 1680c76d32ba48f57424e55e0c5a4c405a365aaa Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Tue, 24 Sep 2024 18:49:23 -0400 Subject: [PATCH 095/149] meta --- source/read.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/read.txt b/source/read.txt index c380d508..2af56092 100644 --- a/source/read.txt +++ b/source/read.txt @@ -10,6 +10,14 @@ Read Data from MongoDB :depth: 2 :class: singlecol +.. facet:: + :name: genre + :values: reference + +.. meta:: + :description: Learn how to use the PHP Library to read data to MongoDB. + :keywords: usage examples, save, crud, read, code example + .. toctree:: :titlesonly: :maxdepth: 1 From 16de291f8a2f03c53c8a40c3283cf9a12e54aa2e Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Wed, 25 Sep 2024 09:30:14 -0400 Subject: [PATCH 096/149] DOCSP-41965: Read and write settings (#146) * DOCSP-41965: Read and write settings * more info * edits * edits * headers * fix link * fix * RR feedback * api docs * fix * fix --- source/databases-collections.txt | 116 +---------- source/includes/read-write-pref.php | 93 +++++++++ source/index.txt | 1 + source/read-write-pref.txt | 288 ++++++++++++++++++++++++++++ 4 files changed, 386 insertions(+), 112 deletions(-) create mode 100644 source/includes/read-write-pref.php create mode 100644 source/read-write-pref.txt diff --git a/source/databases-collections.txt b/source/databases-collections.txt index f031a006..0af58b59 100644 --- a/source/databases-collections.txt +++ b/source/databases-collections.txt @@ -193,10 +193,8 @@ The following example deletes the ``test_collection`` collection: Configure Read and Write Operations ----------------------------------- -You can control how the library routes read operations by setting a **read preference**. -You can also control options for how the library waits for acknowledgment of -read and write operations on a replica set by setting a **read concern** and a -**write concern**. +You can control how read and write operations run on replica sets +by specifying a read preference, read concern, or write concern. By default, databases inherit read and write settings from the ``MongoDB\Client`` instance. Collections inherit these settings from the ``MongoDB\Client`` or @@ -205,114 +203,8 @@ You can change these settings by passing an options array to the ``MongoDB\Client::selectDatabase()``, ``MongoDB\Client::selectCollection()``, or ``MongoDB\Database::selectCollection()`` methods. -To change the read preference, read concern, and write concern of your database -or collection, set the following options in the array parameter: - -- ``readPreference``: Sets the read preference. For a list of available read - preferences, see :php:`MongoDB\Driver\ReadPreference ` - in the extension API documentation. -- ``readConcern``: Sets the read concern. For a list of available read - concerns, see :php:`MongoDB\Driver\ReadConcern ` - in the extension API documentation. -- ``writeConcern``: Sets the write concern. For a list of available write - concerns, see :php:`MongoDB\Driver\WriteConcern ` - in the extension API documentation. - -.. tip:: - - To learn more about read preferences and read and write concerns, see the - following guides in the MongoDB Server manual: - - - :manual:`Read Preference ` - - :manual:`Read Concern ` - - :manual:`Write Concern ` - -Database Configuration Example -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The following example shows how to set the read preference, read concern, and -write concern of a database called ``test_database`` by passing an options -array to ``selectDatabase()``: - -.. literalinclude:: /includes/databases-collections/databases-collections.php - :language: php - :dedent: - :start-after: start-database-settings - :end-before: end-database-settings - -Collection Configuration Example -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The following example shows how to set the read preference, read concern, and -write concern of a collection called ``test_collection`` by passing an options -array to ``selectCollection()``: - -.. literalinclude:: /includes/databases-collections/databases-collections.php - :language: php - :dedent: - :start-after: start-collection-settings - :end-before: end-collection-settings - -Advanced Read Configurations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Tag Sets -```````` - -In {+mdb-server+}, you can apply key-value :manual:`tags -` to replica-set -members according to any criteria you choose. You can then use -those tags to target one or more members for a read operation. - -By default, the {+php-library+} ignores tags when choosing a member -to read from. To instruct the {+php-library+} to prefer certain tags, -pass them as a parameter to your ``MongoDB\Driver\ReadPreference`` class -constructor. Then, set the ``MongoDB\Driver\ReadPreference`` object as -the value of the ``readPreference`` database option. - -This code example sets the ``readPreference`` option to a tag set -that instructs ``test_database`` to prefer reads from secondary replica set -members in the following order: - -1. Members from the New York data center (``['dc' => 'ny']``) -#. Members from the San Francisco data center (``['dc' => 'sf']``) -#. Any secondary members (``[]``) - -.. literalinclude:: /includes/databases-collections/databases-collections.php - :language: php - :dedent: - :start-after: start-tag-set - :end-before: end-tag-set - -Local Threshold -``````````````` - -If multiple replica-set members match the read preference and tag sets you specify, -the {+php-library+} reads from the nearest replica-set members, chosen according to -their ping time. - -By default, the library uses only members whose ping times are within 15 milliseconds -of the nearest member for queries. To distribute reads between members with -higher latencies, pass an options array to the ``MongoDB\Client`` constructor that -sets the ``localThresholdMS`` option. - -The following example specifies a local threshold of 35 milliseconds: - -.. literalinclude:: /includes/databases-collections/databases-collections.php - :language: php - :dedent: - :start-after: start-local-threshold - :end-before: end-local-threshold - -In the preceding example, the {+php-library+} distributes reads among matching members -within 35 milliseconds of the closest member's ping time. - -.. note:: - - The {+php-library+} ignores the value of ``localThresholdMS`` when communicating with a - replica set through a ``mongos`` instance. In this case, use the - :manual:`localThreshold ` - command-line option. +To learn more about setting a read preference, read concern, and write concern, +see the :ref:`php-read-write-pref` guide. API Documentation ----------------- diff --git a/source/includes/read-write-pref.php b/source/includes/read-write-pref.php new file mode 100644 index 00000000..9c0c8ed9 --- /dev/null +++ b/source/includes/read-write-pref.php @@ -0,0 +1,93 @@ + 'secondary', + 'readConcernLevel' => 'local', + 'w' => '2', +]; + +$client = new Client('mongodb://localhost:27017', $clientOptions); +// end-client-settings + +// start-client-settings-uri +$uri = 'mongodb://localhost:27017/?readPreference=secondary&readConcernLevel=local&w=2'; +$client = new Client($uri); +// end-client-settings-uri + +// start-session-settings +$sessionOptions = [ + 'readPreference' => new ReadPreference(ReadPreference::PRIMARY_PREFERRED), + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), +]; + +$session = $client->startSession($sessionOptions); +// end-session-settings + +// start-transaction-settings +$transactionOptions = [ + 'readPreference' => new ReadPreference(ReadPreference::PRIMARY), + 'readConcern' => new ReadConcern(ReadConcern::MAJORITY), + 'writeConcern' => new WriteConcern(1), +]; + +$session->startTransaction($transactionOptions); +// end-transaction-settings + +// Sets read and write settings for the "test_database" database +// start-database-settings +$db = $client->selectDatabase('test_database', [ + 'readPreference' => new ReadPreference(ReadPreference::PRIMARY_PREFERRED), + 'readConcern' => new ReadConcern(ReadConcern::AVAILABLE), + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), +]); +// end-database-settings + +// Sets read and write settings for the "test_collection" collection +// start-collection-settings +$collection = $client->selectCollection('test_database', 'test_collection', [ + 'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED), + 'readConcern' => new ReadConcern(ReadConcern::AVAILABLE), + 'writeConcern' => new WriteConcern(0), +]); + +// end-collection-settings + +// Instructs the library to prefer reads from secondary replica set members +// located in New York, followed by a secondary in San Francisco, and +// lastly fall back to any secondary. +// start-tag-set +$readPreference = new ReadPreference( + ReadPreference::RP_SECONDARY, + [ + ['dc' => 'ny'], + ['dc' => 'sf'], + [], + ], +); + +$db = $client->selectDatabase( + 'test_database', + ['readPreference' => $readPreference], +); + +// end-tag-set + +// Instructs the library to distribute reads between members within 35 milliseconds +// of the closest member's ping time +// start-local-threshold +$options = [ + 'replicaSet' => 'repl0', + 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), + 'localThresholdMS' => 35, +]; + +$client = new Client('mongodb://localhost:27017', [], $options); +// end-local-threshold diff --git a/source/index.txt b/source/index.txt index 44bedaa8..46bed15a 100644 --- a/source/index.txt +++ b/source/index.txt @@ -18,6 +18,7 @@ MongoDB PHP Library /indexes /monitoring /security + /read-write-pref /tutorial /upgrade /reference diff --git a/source/read-write-pref.txt b/source/read-write-pref.txt new file mode 100644 index 00000000..fd324f9d --- /dev/null +++ b/source/read-write-pref.txt @@ -0,0 +1,288 @@ +.. _php-read-write-pref: + +=============================================== +Specify How CRUD Operations Run on Replica Sets +=============================================== + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: customize, preferences, replica set, consistency + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +In this guide, you can learn how to configure **write concern**, **read concern**, +and **read preference** options to modify the way that the {+php-library+} runs create, +read, update, and delete (CRUD) operations on replica sets. + +You can set write concern, read concern, and read preference options at the following +levels: + +- Client, which sets the *default for all operation executions* unless overridden +- Session +- Transaction +- Database +- Collection + +This list also indicates the increasing order of precedence of the option settings. For +example, if you set a read concern level for a transaction, it will override a read +concern level inherited from the client. + +These options allow you to customize the causal consistency and availability of the data +in your replica sets. To see a full list of read preference, read concern, and write concern +options, see the following guides in the {+mdb-server+} manual: + +- :manual:`Read Preference ` +- :manual:`Read Concern ` +- :manual:`Write Concern ` + +.. _php-read-write-config: + +Configure Read and Write Operations +----------------------------------- + +You can control how the library routes read operations by setting a read preference. +You can also control how the library waits for acknowledgment of read and write operations +on a replica set by setting read and write concerns. + +This section shows how to configure the read preference, read concern, and write +concern at various levels by passing an options array parameter to any one of the +following methods: + +- :ref:`MongoDB\Client::__construct() `: Configures client-level + settings +- :ref:`MongoDB\Client::startSession() `: Configures session-level + settings +- :ref:`MongoDB\Driver\Session::startTransaction() `: + Configures transaction-level settings +- :ref:`MongoDB\Client::selectDatabase() `: Configures + database-level settings +- :ref:`MongoDB\Client::selectCollection() `: Configures + collection-level settings + +.. _php-read-write-client: + +Client Configuration +~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a ``MongoDB\Client`` instance by passing an array to +the constructor. The code configures the following settings: + +- ``secondary`` read preference: Read operations retrieve data from + secondary replica set members +- ``local`` read concern: Read operations return the instance's most recent data + without guaranteeing that the data has been written to a majority of the replica + set members +- ``2`` write concern: The primary and one secondary replica set member + must acknowledge the write operation + +.. literalinclude:: /includes/read-write-pref.php + :language: php + :dedent: + :start-after: start-client-settings + :end-before: end-client-settings + +Alternatively, you can specify the read and write settings in the connection +URI, which is passed as a parameter to the ``MongoDB\Client`` constructor: + +.. literalinclude:: /includes/read-write-pref.php + :language: php + :dedent: + :start-after: start-client-settings-uri + :end-before: end-client-settings-uri + +.. note:: + + The ``readPreference``, ``readConcernLevel``, and ``w`` client options accept + string values. When configuring read and write settings at any other level, + you must assign values of type ``MongoDB\Driver\ReadPreference``, + ``MongoDB\Driver\ReadConcern``, and ``MongoDB\Driver\WriteConcern`` to the corresponding + options. + +.. _php-read-write-session: + +Session Configuration +~~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a session by passing an array to the ``startSession()`` +method. The code configures the following settings: + +- ``PRIMARY_PREFERRED`` read preference: Read operations retrieve data from + the primary replica set member, or secondary members if the primary is unavailable +- ``LOCAL`` read concern: Read operations return the instance's most recent data + without guaranteeing that the data has been written to a majority of the replica + set members +- ``MAJORITY`` write concern: The majority of all replica set members + must acknowledge the write operation + +.. literalinclude:: /includes/read-write-pref.php + :language: php + :dedent: + :start-after: start-session-settings + :end-before: end-session-settings + +.. _php-read-write-transaction: + +Transaction Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a transaction by passing an array to the ``startTransaction()`` +method. The code configures the following settings: + +- ``PRIMARY`` read preference: Read operations retrieve data from + the primary replica set member +- ``MAJORITY`` read concern: Read operations return the instance's most recent data + that has been written to a majority of replica set members +- ``1`` write concern: The primary replica set member must acknowledge the + write operation + +.. literalinclude:: /includes/read-write-pref.php + :language: php + :dedent: + :start-after: start-transaction-settings + :end-before: end-transaction-settings + +.. _php-read-write-database: + +Database Configuration +~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a database called ``test_database`` by passing an options +array to the ``selectDatabase()`` method. The code configures the following settings: + +- ``PRIMARY_PREFERRED`` read preference: Read operations retrieve data from + the primary replica set member, or secondary members if the primary is unavailable +- ``AVAILABLE`` read concern: Read operations return the instance's most recent data + without guaranteeing that the data has been written to a majority of the replica + set members +- ``MAJORITY`` write concern: The majority of all replica set members + must acknowledge the write operation + +.. literalinclude:: /includes/read-write-pref.php + :language: php + :dedent: + :start-after: start-database-settings + :end-before: end-database-settings + +.. _php-read-write-collection: + +Collection Configuration +~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how to set the read preference, read concern, and +write concern of a collection called ``test_collection`` by passing an options +array to the ``selectCollection()`` method. The code configures the following settings: + +- ``SECONDARY_PREFERRED`` read preference: Read operations retrieve data from + secondary replica set members, or the primary members if no secondaries are available +- ``AVAILABLE`` read concern: Read operations return the instance's most recent data + without guaranteeing that the data has been written to a majority of the replica + set members +- ``0`` write concern: Requests no acknowledgment of the write operation + +.. literalinclude:: /includes/read-write-pref.php + :language: php + :dedent: + :start-after: start-collection-settings + :end-before: end-collection-settings + +.. _php-read-write-advanced: + +Advanced Read Configurations +---------------------------- + +This section shows how to further customize your read operation +settings in the following ways: + +- :ref:`Apply a tag set ` +- :ref:`Specify a local threshold ` + +.. _php-tag-sets: + +Tag Sets +~~~~~~~~ + +The {+mdb-server+} allows you to apply key-value :manual:`tags +` to replica-set +members according to any criteria you choose. You can then use +those tags to target one or more members for a read operation. + +By default, the {+php-library+} ignores tags when choosing a member +to read from. To instruct the {+php-library+} to prefer certain tags, +pass them as a parameter to your ``MongoDB\Driver\ReadPreference`` class +constructor. Then, set the ``MongoDB\Driver\ReadPreference`` object as +the value of the ``readPreference`` database option. + +Suppose you are connected to a replica set that contains members hosted +at multiple data centers across the United States. This code example sets +the ``readPreference`` option to a tag set that instructs ``test_database`` +to prefer reads from secondary replica set members in the following order: + +1. Members from the New York data center (``['dc' => 'ny']``) +#. Members from the San Francisco data center (``['dc' => 'sf']``) +#. Any secondary members (``[]``) + +.. literalinclude:: /includes/read-write-pref.php + :language: php + :dedent: + :start-after: start-tag-set + :end-before: end-tag-set + +.. _php-local-threshold: + +Local Threshold +~~~~~~~~~~~~~~~ + +If multiple replica-set members match the read preference and tag sets you specify, +the {+php-library+} reads from the nearest replica-set members, chosen according to +their ping time. + +By default, the library uses only members whose ping times are within 15 milliseconds +of the nearest member for queries. To distribute reads between members with +higher latencies, pass an options array to the ``MongoDB\Client`` constructor that +sets the ``localThresholdMS`` option. + +The following example specifies a local threshold of 35 milliseconds: + +.. literalinclude:: /includes/read-write-pref.php + :language: php + :dedent: + :start-after: start-local-threshold + :end-before: end-local-threshold + +In the preceding example, the {+php-library+} distributes reads among matching members +within 35 milliseconds of the closest member's ping time. + +.. note:: + + The {+php-library+} ignores the value of ``localThresholdMS`` when communicating with a + replica set through a ``mongos`` instance. In this case, use the + :manual:`localThreshold ` + command-line option. + +API Documentation +----------------- + +To learn more about any of the methods or types discussed in this +guide, see the following library API documentation: + +- :phpmethod:`MongoDB\Client::__construct()` +- :phpmethod:`MongoDB\Client::startSession()` +- :phpmethod:`MongoDB\Client::selectDatabase()` +- :phpmethod:`MongoDB\Client::selectCollection()` + +To learn more about the ``startTransaction()`` method, see :php:`MongoDB\Driver\Session::startTransaction() +` in the extension API documentation. From 855563cd085e992926efd312b8e1909f4b9a30f6 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Wed, 25 Sep 2024 11:30:57 -0400 Subject: [PATCH 097/149] DOCSP-41950: Landing page (#150) * DOCSP-41950: Landing page * fix build errors * fixes, data formats * toc * fix * data formats folder * RR feedback * fix * remove file --- snooty.toml | 6 +- source/compatibility.txt | 2 - source/connect/client.txt | 6 +- source/connect/connection-targets.txt | 6 +- source/connect/tls.txt | 30 +- source/data-formats.txt | 40 + source/{tutorial => data-formats}/codecs.txt | 0 .../custom-types.txt | 2 + .../{tutorial => data-formats}/decimal128.txt | 2 + .../modeling-bson-data.txt | 2 + source/faq.txt | 2 + source/index.txt | 121 ++- source/read/count.txt | 2 +- source/tutorial.txt | 2 + source/tutorial/aws-lambda.txt | 2 + source/tutorial/collation.txt | 2 + source/tutorial/commands.txt | 2 + source/tutorial/connecting.txt | 25 - source/tutorial/crud.txt | 792 ------------------ source/tutorial/encryption.txt | 2 + source/tutorial/example-data.txt | 47 -- source/tutorial/gridfs.txt | 214 ----- source/tutorial/indexes.txt | 139 --- source/tutorial/server-selection.txt | 2 + source/tutorial/stable-api.txt | 93 -- source/tutorial/tailable-cursor.txt | 190 ----- source/upgrade.txt | 369 -------- 27 files changed, 165 insertions(+), 1937 deletions(-) create mode 100644 source/data-formats.txt rename source/{tutorial => data-formats}/codecs.txt (100%) rename source/{tutorial => data-formats}/custom-types.txt (99%) rename source/{tutorial => data-formats}/decimal128.txt (99%) rename source/{tutorial => data-formats}/modeling-bson-data.txt (99%) delete mode 100644 source/tutorial/connecting.txt delete mode 100644 source/tutorial/crud.txt delete mode 100644 source/tutorial/example-data.txt delete mode 100644 source/tutorial/gridfs.txt delete mode 100644 source/tutorial/indexes.txt delete mode 100644 source/tutorial/stable-api.txt delete mode 100644 source/tutorial/tailable-cursor.txt delete mode 100644 source/upgrade.txt diff --git a/snooty.toml b/snooty.toml index 938cdc0d..efd33899 100644 --- a/snooty.toml +++ b/snooty.toml @@ -22,8 +22,10 @@ toc_landing_pages = [ "/reference/class/MongoDBModelDatabaseInfo", "/reference/class/MongoDBModelIndexInfo", "/get-started", + "/databases-collections", "/write", - "/indexes" + "/indexes", + "/data-formats" ] sharedinclude_root = "https://raw.githubusercontent.com/10gen/docs-shared/main/" @@ -33,7 +35,7 @@ php-library = "MongoDB PHP Library" [constants] php-library = "MongoDB PHP Library" -driver-short = "PHP library" +library-short = "PHP library" stable-api = "Stable API" mdb-server = "MongoDB Server" api = "https://www.mongodb.com/docs/php-library/current/reference" diff --git a/source/compatibility.txt b/source/compatibility.txt index b3362b5a..acca9855 100644 --- a/source/compatibility.txt +++ b/source/compatibility.txt @@ -44,8 +44,6 @@ The first column lists the version of the library and extension. .. include:: /includes/language-compatibility-table-php.rst -.. sharedinclude:: dbx/about-driver-compatibility.rst - For more information on how to read the compatibility tables, see our guide on :ref:`MongoDB Compatibility Tables `. diff --git a/source/connect/client.txt b/source/connect/client.txt index 421f6fa2..680d293b 100644 --- a/source/connect/client.txt +++ b/source/connect/client.txt @@ -22,13 +22,13 @@ Overview To connect to a MongoDB deployment, you must create the following items: -- **Connection URI**, also known as a *connection string*, which tells the {+driver-short+} +- **Connection URI**, also known as a *connection string*, which tells the {+library-short+} which MongoDB deployment to connect to. - **MongoDB\\Client** object, which creates the connection to the MongoDB deployment and lets you perform operations on it. You can also set options within either or both of these components to -customize the way that the {+driver-short+} behaves +customize the way that the {+library-short+} behaves while connected to MongoDB. This guide describes the components of a connection string and shows how to @@ -99,7 +99,7 @@ deployment on port ``27017`` of ``localhost``: API Documentation ----------------- -To learn more about creating a ``MongoDB\Client`` object in the {+driver-short+}, +To learn more about creating a ``MongoDB\Client`` object in the {+library-short+}, see the following API documentation: - :ref:`MongoDB\Client ` \ No newline at end of file diff --git a/source/connect/connection-targets.txt b/source/connect/connection-targets.txt index 1047dc6d..ed4441c2 100644 --- a/source/connect/connection-targets.txt +++ b/source/connect/connection-targets.txt @@ -42,7 +42,7 @@ breaking changes when Atlas upgrades to a new version of {+mdb-server+}. To learn more about the {+stable-api+} feature, see the :ref:`{+stable-api+} page `. -The following code shows how to use the {+driver-short+} to connect to an Atlas cluster. +The following code shows how to use the {+library-short+} to connect to an Atlas cluster. The code also uses the ``serverApi`` option to specify a {+stable-api+} version. .. literalinclude:: /includes/connect/atlas.php @@ -63,7 +63,7 @@ To connect to a local MongoDB deployment, use ``localhost`` as the hostname. By default, the ``mongod`` process runs on port 27017, though you can customize this for your deployment. -The following code shows how to use the {+driver-short+} to connect to a local MongoDB +The following code shows how to use the {+library-short+} to connect to a local MongoDB deployment: .. literalinclude:: /includes/connect/client.php @@ -79,7 +79,7 @@ To connect to a replica set, specify the hostnames (or IP addresses) and port numbers of the replica set members in your connection string. If you aren't able to provide a full list of hosts in the replica set, you can -specify one or more of the hosts in the replica set and instruct the {+driver-short+} to +specify one or more of the hosts in the replica set and instruct the {+library-short+} to perform automatic discovery to find the others. To instruct the driver to perform automatic discovery, choose one of the following actions: diff --git a/source/connect/tls.txt b/source/connect/tls.txt index f5e6fe23..e8051122 100644 --- a/source/connect/tls.txt +++ b/source/connect/tls.txt @@ -23,7 +23,7 @@ Overview In this guide, you can learn how to use the :wikipedia:`TLS ` protocol to secure your connection to a MongoDB deployment. -When you enable TLS for a connection, the {+driver-short+} performs the following actions: +When you enable TLS for a connection, the {+library-short+} performs the following actions: - Uses TLS to connect to the MongoDB deployment - Verifies the deployment's certificate @@ -41,7 +41,7 @@ To learn how to configure your MongoDB deployment for TLS, see the .. tip:: - The {+driver-short+} delegates most TLS behavior to the MongoDB C Driver. + The {+library-short+} delegates most TLS behavior to the MongoDB C Driver. For information about how the C driver handles TLS, including configuration steps and expected behavior, see `Configuring TLS `__ @@ -78,7 +78,7 @@ signed by a well-known CA (certificate authority), and your application relies o to validate the certificate. During testing, however, you might want to act as your own CA. -In this case, you must instruct the {+driver-short+} to +In this case, you must instruct the {+library-short+} to use your CA certificates instead of ones signed by another CA. To do so, use the ``tlsCAFile`` connection option to specify the path to a ``.pem`` file @@ -95,7 +95,7 @@ Specify a CA Directory If you are using OpenSSL or LibreSSL (``libtls``) for TLS support, you can also use the ``ca_dir`` option to instruct -the {+driver-short+} to search for a CA file within a directory. The driver searches this +the {+library-short+} to search for a CA file within a directory. The driver searches this directory if it doesn't find a CA file at the path specified in the ``tlsCAFile`` option. The following code example shows how to use the ``driverOptions`` parameter to specify the @@ -119,7 +119,7 @@ Check Certificate Revocation ---------------------------- When an X.509 certificate is no longer trustworthy—for example, if its private key -has been compromised—the CA revokes the certificate. The {+driver-short+} includes two ways +has been compromised—the CA revokes the certificate. The {+library-short+} includes two ways to check whether a server's certificate has been revoked. .. _php-disable-ocsp: @@ -131,15 +131,15 @@ The Online Certificate Status Protocol (OCSP) process varies depending on the ve {+mdb-server+} you're connecting to: - **MongoDB v4.4 or later:** The server staples a - time-stamped OCSP response to its certificate. The {+driver-short+} validates the certificate + time-stamped OCSP response to its certificate. The {+library-short+} validates the certificate against the OCSP response. If the CA has revoked the certificate, or if the OCSP response is otherwise invalid, the TLS handshake fails. -- **MongoDB v4.3 or earlier:** The server supplies an OCSP endpoint, which the {+driver-short+} - contacts directly. The {+driver-short+} then validates the certificate against the OCSP +- **MongoDB v4.3 or earlier:** The server supplies an OCSP endpoint, which the {+library-short+} + contacts directly. The {+library-short+} then validates the certificate against the OCSP response. If the CA hasn't revoked the certificate, the TLS handshake continues, even if the OCSP response is invalid or malformed. -To stop the {+driver-short+} from contacting the OCSP endpoint, set the +To stop the {+library-short+} from contacting the OCSP endpoint, set the ``tlsDisableOCSPEndpointCheck`` connection option to ``true``. You can do this in two ways: by passing an argument to the ``MongoDB\Client`` constructor or through a parameter in your connection string. @@ -148,7 +148,7 @@ You can do this in two ways: by passing an argument to the .. note:: - Even if the ``tlsDisableOCSPEndpointCheck`` option is set to ``true``, the {+driver-short+} + Even if the ``tlsDisableOCSPEndpointCheck`` option is set to ``true``, the {+library-short+} still verifies any OCSP response stapled to a server's certificate. .. _php-crl: @@ -156,7 +156,7 @@ You can do this in two ways: by passing an argument to the Certificate Revocation List ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Instead of using OCSP, you can use the instruct the {+driver-short+} +Instead of using OCSP, you can use the instruct the {+library-short+} to check the server's certificate against a Certificate Revocation List (CRL) published by the CA. To do so, set the ``crl_file`` option to the file path of the CRL. Include this option in the @@ -177,7 +177,7 @@ Present a Client Certificate ---------------------------- Some MongoDB deployments require every connecting application to present a client certificate -that proves its identity. To specify the client certificate for the {+driver-short+} to +that proves its identity. To specify the client certificate for the {+library-short+} to present, set the ``tleCertificateKeyFile`` option to the file path of the ``.pem`` file that contains your certificate and private key. @@ -214,7 +214,7 @@ of the ``MongoDB\Client`` constructor or through a parameter in your connection Allow Insecure TLS ------------------ -When TLS is enabled, the {+driver-short+} automatically verifies the certificate that +When TLS is enabled, the {+library-short+} automatically verifies the certificate that the server presents. When testing your code, you can disable this verification. This is known as *insecure TLS.* @@ -262,7 +262,7 @@ To disable only hostname verification, set the ``tlsAllowInvalidHostnames`` opti API Documentation ----------------- -To learn more about configuring TLS for the {+driver-short+}, +To learn more about configuring TLS for the {+library-short+}, see the following API documentation: -- :ref:`MongoDB\Client ` \ No newline at end of file +- :phpclass:`MongoDB\Client` \ No newline at end of file diff --git a/source/data-formats.txt b/source/data-formats.txt new file mode 100644 index 00000000..ca4e482a --- /dev/null +++ b/source/data-formats.txt @@ -0,0 +1,40 @@ +.. _php-data-formats: + +======================== +Specialized Data Formats +======================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: store, bson, codec + +.. toctree:: + :titlesonly: + :maxdepth: 1 + + /data-formats/custom-types + /data-formats/codecs + /data-formats/decimal128 + /data-formats/modeling-bson-data + + +Overview +-------- + +You can use several types of specialized data formats in your {+library-short+} +application. To learn how to work with these data formats, see the following +guides: + +- :ref:`php-custom-types` +- :ref:`php-codecs` +- :ref:`php-decimal128` +- :ref:`php-bson` \ No newline at end of file diff --git a/source/tutorial/codecs.txt b/source/data-formats/codecs.txt similarity index 100% rename from source/tutorial/codecs.txt rename to source/data-formats/codecs.txt diff --git a/source/tutorial/custom-types.txt b/source/data-formats/custom-types.txt similarity index 99% rename from source/tutorial/custom-types.txt rename to source/data-formats/custom-types.txt index 243d7e52..f6cb7fb9 100644 --- a/source/tutorial/custom-types.txt +++ b/source/data-formats/custom-types.txt @@ -1,3 +1,5 @@ +.. _php-custom-types: + ================= Custom Data-Types ================= diff --git a/source/tutorial/decimal128.txt b/source/data-formats/decimal128.txt similarity index 99% rename from source/tutorial/decimal128.txt rename to source/data-formats/decimal128.txt index 2397ccd8..523b6ac8 100644 --- a/source/tutorial/decimal128.txt +++ b/source/data-formats/decimal128.txt @@ -1,3 +1,5 @@ +.. _php-decimal128: + ========== Decimal128 ========== diff --git a/source/tutorial/modeling-bson-data.txt b/source/data-formats/modeling-bson-data.txt similarity index 99% rename from source/tutorial/modeling-bson-data.txt rename to source/data-formats/modeling-bson-data.txt index 5429b031..12424275 100644 --- a/source/tutorial/modeling-bson-data.txt +++ b/source/data-formats/modeling-bson-data.txt @@ -1,3 +1,5 @@ +.. _php-bson: + ================== Modeling BSON Data ================== diff --git a/source/faq.txt b/source/faq.txt index 101f757f..5e333636 100644 --- a/source/faq.txt +++ b/source/faq.txt @@ -1,3 +1,5 @@ +.. _php-faq: + ========================== Frequently Asked Questions ========================== diff --git a/source/index.txt b/source/index.txt index 46bed15a..7ffdd83a 100644 --- a/source/index.txt +++ b/source/index.txt @@ -14,73 +14,110 @@ MongoDB PHP Library /databases-collections /read /write + /read-write-pref /aggregation /indexes /monitoring /security - /read-write-pref - /tutorial - /upgrade - /reference - FAQ + /data-formats /compatibility /whats-new + FAQ + /reference + +Overview +-------- + +Welcome to the documentation site for the official {+php-library+}. -The |php-library| provides a high-level abstraction around the lower-level +The {+library-short+} provides a high-level abstraction around the lower-level :php:`mongodb extension `. -The ``mongodb`` extension provides a limited API to connect to the database and -execute generic commands, queries, and write operations. In contrast, the -|php-library| provides a full-featured API and models client, database, and -collection objects. Each of those classes provide various helper methods for -performing operations in context. For example, :phpclass:`MongoDB\Collection` -implements methods for executing CRUD operations and managing indexes on the -collection, among other things. +The ``mongodb`` extension provides a limited API to connect to a MongoDB +database and execute generic commands, queries, and write operations. In +contrast, the {+library-short+} provides a full-featured API and models client, +database, and collection objects. If you are developing a PHP application with +MongoDB, consider using the {+library-short+} instead of the extension alone. + +Get Started +----------- + +Learn how to install the library and extension, establish a connection to MongoDB, +and begin working with data in the :ref:`php-get-started` tutorial. + +Connect to MongoDB +------------------ + +Learn how to create and configure a connection to a MongoDB deployment +in the :ref:`php-connect` section. + +Databases and Collections +------------------------- + +Learn how to use the {+library-short+} to work with MongoDB databases and collections +in the :ref:`php-databases-collections` section. + +Read Data from MongoDB +---------------------- + +Learn how you can retrieve data from MongoDB in the :ref:`php-read` section. -If you are developing a PHP application with MongoDB, you should consider using -the |php-library| instead of the extension alone. +Write Data to MongoDB +--------------------- -New to the PHP Library? ------------------------ +Learn how you can write data to MongoDB in the :ref:`php-write` section. -If you have some experience with MongoDB but are new to the PHP library, the -following pages should help you get started: +Transform Your Data with Aggregation +------------------------------------ -- :ref:`php-download-and-install` +Learn how to use the {+library-short+} to perform aggregation operations in the +:ref:`php-aggregation` section. -- :doc:`/tutorial/connecting` +Optimize Queries with Indexes +----------------------------- -- :doc:`/tutorial/crud` +Learn how to work with common types of indexes in the :ref:`php-indexes` +section. -- :doc:`/tutorial/commands` +Monitoring +---------- -- :doc:`/tutorial/gridfs` +Learn how to monitor change events in the :ref:`php-monitoring` +section. -- :doc:`/tutorial/modeling-bson-data` +Secure Your Data +---------------- -- :doc:`/reference/bson` +Learn about ways you can authenticate your application and encrypt your data in +the :ref:`php-security` section. -Code examples can be found in the ``examples`` directory in the source code. +Specialized Data Formats +------------------------ -If you have previously worked with the legacy ``mongo`` extension, it will be -helpful to review the :doc:`/upgrade` for a summary of API changes between the -old driver and this library. +Learn how to work with specialized data formats and custom types in the +:ref:`php-data-formats` section. -You can view changes introduced in each version release of the -{+php-library+} in the :ref:`php-lib-whats-new` section. +Compatibility +------------- -New to MongoDB? ---------------- +See compatibility tables showing the recommended {+library-short+} version to use for +specific PHP and {+mdb-server+} versions in the :ref:`php-compatibility` section. -If you are a new MongoDB user, the following links should help you become more -familiar with MongoDB and introduce some of the concepts and terms you will -encounter in the library documentation: +What's New +---------- -- :manual:`Introduction to MongoDB ` +Learn about new features and changes in each version in the :ref:`` +section. -- :manual:`Databases and Collections ` +.. TODO: + Upgrade {+library-short+} Versions + ---------------------------------- + + .. Learn what changes you must make to your application to upgrade driver versions + .. in the :ref:`php-upgrade` section. -- :manual:`Documents ` and - :manual:`BSON Types ` +FAQ +--- -- :manual:`MongoDB CRUD Operations ` +See answers to commonly asked questions about the {+library-short+} in the +the :ref:`php-faq` section. \ No newline at end of file diff --git a/source/read/count.txt b/source/read/count.txt index 5b825a78..20d7dd71 100644 --- a/source/read/count.txt +++ b/source/read/count.txt @@ -25,7 +25,7 @@ and estimated count of the number of documents in a collection. The following me count documents in a collection: - ``MongoDB\Collection::countDocuments()``: Returns the exact number of documents that - match a query filter or that exist in a collection + match a query filter or that exist in a collection - ``MongoDB\Collection::estimatedDocumentCount()``: Returns the estimated number of documents in a collection diff --git a/source/tutorial.txt b/source/tutorial.txt index f50c19c8..4ea6c7fa 100644 --- a/source/tutorial.txt +++ b/source/tutorial.txt @@ -1,3 +1,5 @@ +:orphan: + Tutorials ========= diff --git a/source/tutorial/aws-lambda.txt b/source/tutorial/aws-lambda.txt index efce81fc..cb27689f 100644 --- a/source/tutorial/aws-lambda.txt +++ b/source/tutorial/aws-lambda.txt @@ -1,3 +1,5 @@ +:orphan: + ============================== Deploy to AWS Lambda with Bref ============================== diff --git a/source/tutorial/collation.txt b/source/tutorial/collation.txt index 6ba335e7..ce6a06fd 100644 --- a/source/tutorial/collation.txt +++ b/source/tutorial/collation.txt @@ -1,3 +1,5 @@ +:orphan: + ========= Collation ========= diff --git a/source/tutorial/commands.txt b/source/tutorial/commands.txt index 1debe37b..ff0de205 100644 --- a/source/tutorial/commands.txt +++ b/source/tutorial/commands.txt @@ -1,3 +1,5 @@ +:orphan: + ========================= Execute Database Commands ========================= diff --git a/source/tutorial/connecting.txt b/source/tutorial/connecting.txt deleted file mode 100644 index cffd19ef..00000000 --- a/source/tutorial/connecting.txt +++ /dev/null @@ -1,25 +0,0 @@ -===================== -Connecting to MongoDB -===================== - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Creating a Client instance --------------------------------------------------------- - -.. include:: /reference/method/MongoDBClient__construct.txt - :start-after: start-connecting-include - :end-before: end-connecting-include - -Specifying connection options ------------------------------ - -Connection options can be passed via the ``$uri`` parameter, or through the -``$options`` and ``$driverOptions`` parameters. The available options are -documented in the :phpmethod:`MongoDB\Client::__construct()` reference. diff --git a/source/tutorial/crud.txt b/source/tutorial/crud.txt deleted file mode 100644 index 036e176f..00000000 --- a/source/tutorial/crud.txt +++ /dev/null @@ -1,792 +0,0 @@ -=============== -CRUD Operations -=============== - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - - -CRUD operations *create*, *read*, *update*, and *delete* documents. The -|php-library|'s :phpclass:`MongoDB\Collection` class implements MongoDB's -cross-driver `CRUD specification -`_, -providing access to methods for inserting, finding, updating, and deleting -documents in MongoDB. - -This document provides a general introduction to inserting, querying, updating, -and deleting documents using the |php-library|. The MongoDB Manual's -:manual:`CRUD Section ` provides a more thorough introduction to CRUD -operations with MongoDB. - -Insert Documents ----------------- - -Insert One Document -~~~~~~~~~~~~~~~~~~~ - -The :phpmethod:`MongoDB\Collection::insertOne()` method inserts a single -document into MongoDB and returns an instance of -:phpclass:`MongoDB\InsertOneResult`, which you can use to access the ID of the -inserted document. - -.. this uses the insertOne example from the method reference: - -.. include:: /reference/method/MongoDBCollection-insertOne.txt - :start-after: start-crud-include - :end-before: end-crud-include - -The output includes the ID of the inserted document. - -If you include an ``_id`` value when inserting a document, MongoDB checks to -ensure that the ``_id`` value is unique for the collection. If the ``_id`` value -is not unique, the insert operation fails due to a duplicate key error. - -The following example inserts a document while specifying the value for the -``_id``: - -.. code-block:: php - - test->users; - - $insertOneResult = $collection->insertOne(['_id' => 1, 'name' => 'Alice']); - - printf("Inserted %d document(s)\n", $insertOneResult->getInsertedCount()); - - var_dump($insertOneResult->getInsertedId()); - -The output would then resemble: - -.. code-block:: none - - Inserted 1 document(s) - int(1) - -.. seealso:: - - :phpmethod:`MongoDB\Collection::insertOne()` - -Insert Many Documents -~~~~~~~~~~~~~~~~~~~~~ - -The :phpmethod:`MongoDB\Collection::insertMany()` method allows you to insert -multiple documents in one write operation and returns an instance of -:phpclass:`MongoDB\InsertManyResult`, which you can use to access the IDs of -the inserted documents. - -.. this uses the insertMany example from the method reference: - -.. include:: /reference/method/MongoDBCollection-insertMany.txt - :start-after: start-crud-include - :end-before: end-crud-include - -.. seealso:: - - :phpmethod:`MongoDB\Collection::insertMany()` - -Query Documents ---------------- - -The |php-library| provides the :phpmethod:`MongoDB\Collection::findOne()` and -:phpmethod:`MongoDB\Collection::find()` methods for querying documents and the -:phpmethod:`MongoDB\Collection::aggregate()` method for performing -:manual:`aggregation operations `. - -.. include:: /includes/extracts/note-bson-comparison.rst - -Find One Document -~~~~~~~~~~~~~~~~~ - -:phpmethod:`MongoDB\Collection::findOne()` returns the :term:`first document -` that matches the query or ``null`` if no document matches the -query. - -The following example searches for the document with ``_id`` of ``"94301"``: - -.. code-block:: php - - test->zips; - - $document = $collection->findOne(['_id' => '94301']); - - var_dump($document); - -The output would then resemble: - -.. code-block:: none - - object(MongoDB\Model\BSONDocument)#13 (1) { - ["storage":"ArrayObject":private]=> - array(5) { - ["_id"]=> - string(5) "94301" - ["city"]=> - string(9) "PALO ALTO" - ["loc"]=> - object(MongoDB\Model\BSONArray)#12 (1) { - ["storage":"ArrayObject":private]=> - array(2) { - [0]=> - float(-122.149685) - [1]=> - float(37.444324) - } - } - ["pop"]=> - int(15965) - ["state"]=> - string(2) "CA" - } - } - -.. note:: - - The criteria in this example matched an ``_id`` with a string value of - ``"94301"``. The same criteria would not have matched a document with an - integer value of ``94301`` due to MongoDB's :manual:`comparison rules for - BSON types `. Similarly, users should - use a :php:`MongoDB\BSON\ObjectId ` object - when matching an ``_id`` with an :manual:`ObjectId ` - value, as strings and ObjectIds are not directly comparable. - -.. seealso:: - - :phpmethod:`MongoDB\Collection::findOne()` - -.. _php-find-many-documents: - -Find Many Documents -~~~~~~~~~~~~~~~~~~~ - -:phpmethod:`MongoDB\Collection::find()` returns a -:php:`MongoDB\Driver\Cursor ` object, which you can -iterate upon to access all matched documents. - -The following example lists the documents in the ``zips`` collection with the -specified city and state values: - -.. code-block:: php - - test->zips; - - $cursor = $collection->find(['city' => 'JERSEY CITY', 'state' => 'NJ']); - - foreach ($cursor as $document) { - echo $document['_id'], "\n"; - } - -The output would resemble: - -.. code-block:: none - - 07302 - 07304 - 07305 - 07306 - 07307 - 07310 - -.. seealso:: - - :phpmethod:`MongoDB\Collection::find()` - -.. _php-query-projection: - -Query Projection -~~~~~~~~~~~~~~~~ - -By default, queries in MongoDB return all fields in matching documents. To limit -the amount of data that MongoDB sends to applications, you can include a -:manual:`projection document ` in -the query operation. - -.. note:: - - MongoDB includes the ``_id`` field by default unless you explicitly exclude - it in a projection document. - -The following example finds restaurants based on the ``cuisine`` and ``borough`` -fields and uses a :manual:`projection -` to limit the fields that are -returned. It also limits the results to 5 documents. - -.. code-block:: php - - test->restaurants; - - $cursor = $collection->find( - [ - 'cuisine' => 'Italian', - 'borough' => 'Manhattan', - ], - [ - 'projection' => [ - 'name' => 1, - 'borough' => 1, - 'cuisine' => 1, - ], - 'limit' => 4, - ] - ); - - foreach($cursor as $restaurant) { - var_dump($restaurant); - }; - -The output would then resemble: - -.. code-block:: none - - object(MongoDB\Model\BSONDocument)#10 (1) { - ["storage":"ArrayObject":private]=> - array(4) { - ["_id"]=> - object(MongoDB\BSON\ObjectId)#8 (1) { - ["oid"]=> - string(24) "576023c6b02fa9281da3f983" - } - ["borough"]=> - string(9) "Manhattan" - ["cuisine"]=> - string(7) "Italian" - ["name"]=> - string(23) "Isle Of Capri Resturant" - } - } - object(MongoDB\Model\BSONDocument)#13 (1) { - ["storage":"ArrayObject":private]=> - array(4) { - ["_id"]=> - object(MongoDB\BSON\ObjectId)#12 (1) { - ["oid"]=> - string(24) "576023c6b02fa9281da3f98d" - } - ["borough"]=> - string(9) "Manhattan" - ["cuisine"]=> - string(7) "Italian" - ["name"]=> - string(18) "Marchis Restaurant" - } - } - object(MongoDB\Model\BSONDocument)#8 (1) { - ["storage":"ArrayObject":private]=> - array(4) { - ["_id"]=> - object(MongoDB\BSON\ObjectId)#10 (1) { - ["oid"]=> - string(24) "576023c6b02fa9281da3f99b" - } - ["borough"]=> - string(9) "Manhattan" - ["cuisine"]=> - string(7) "Italian" - ["name"]=> - string(19) "Forlinis Restaurant" - } - } - object(MongoDB\Model\BSONDocument)#12 (1) { - ["storage":"ArrayObject":private]=> - array(4) { - ["_id"]=> - object(MongoDB\BSON\ObjectId)#13 (1) { - ["oid"]=> - string(24) "576023c6b02fa9281da3f9a8" - } - ["borough"]=> - string(9) "Manhattan" - ["cuisine"]=> - string(7) "Italian" - ["name"]=> - string(22) "Angelo Of Mulberry St." - } - } - -Limit, Sort, and Skip Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In addition to :ref:`projection criteria `, you can -specify options to limit, sort, and skip documents during queries. - -The following example uses the ``limit`` and ``sort`` options to query for the -five most populous zip codes in the United States: - -.. code-block:: php - - test->zips; - - $cursor = $collection->find( - [], - [ - 'limit' => 5, - 'sort' => ['pop' => -1], - ] - ); - - foreach ($cursor as $document) { - printf("%s: %s, %s\n", $document['_id'], $document['city'], $document['state']); - } - -The output would then resemble: - -.. code-block:: none - - 60623: CHICAGO, IL - 11226: BROOKLYN, NY - 10021: NEW YORK, NY - 10025: NEW YORK, NY - 90201: BELL GARDENS, CA - -Regular Expressions -~~~~~~~~~~~~~~~~~~~ - -Filter criteria may include regular expressions, either by using the -:php:`MongoDB\BSON\Regex ` class directory or the -:query:`$regex` operator. - -The following example lists documents in the ``zips`` collection where the city -name starts with "garden" and the state is Texas: - -.. code-block:: php - - test->zips; - - $cursor = $collection->find([ - 'city' => new MongoDB\BSON\Regex('^garden', 'i'), - 'state' => 'TX', - ]); - - foreach ($cursor as $document) { - printf("%s: %s, %s\n", $document['_id'], $document['city'], $document['state']); - } - -The output would then resemble: - -.. code-block:: none - - 78266: GARDEN RIDGE, TX - 79739: GARDEN CITY, TX - 79758: GARDENDALE, TX - -An equivalent filter could be constructed using the :query:`$regex` operator: - -.. code-block:: php - - ['$regex' => '^garden', '$options' => 'i'], - 'state' => 'TX', - ] - -.. seealso:: - - :manual:`$regex ` in the MongoDB manual - -Although MongoDB's regular expression syntax is not exactly the same as PHP's -:php:`PCRE ` syntax, :php:`preg_quote() ` -may be used to escape special characters that should be matched as-is. The -following example finds restaurants whose name starts with "(Library)": - -.. code-block:: php - - test->restaurants; - - $cursor = $collection->find([ - 'name' => new MongoDB\BSON\Regex('^' . preg_quote('(Library)')), - ]); - -Complex Queries with Aggregation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -MongoDB's :manual:`Aggregation Framework ` allows -you to issue complex queries that filter, transform, and group collection data. -The |php-library|\'s :phpmethod:`MongoDB\Collection::aggregate()` method -returns a :php:`Traversable ` object, which you can iterate upon to -access the results of the aggregation operation. Refer to the -:phpmethod:`MongoDB\Collection::aggregate()` method's :ref:`behavior -reference ` for more about the method's output. - -The following example lists the 5 US states with the most zip codes associated -with them: - -.. code-block:: php - - test->zips; - - $cursor = $collection->aggregate([ - ['$group' => ['_id' => '$state', 'count' => ['$sum' => 1]]], - ['$sort' => ['count' => -1]], - ['$limit' => 5], - ]); - - foreach ($cursor as $state) { - printf("%s has %d zip codes\n", $state['_id'], $state['count']); - } - -The output would then resemble: - -.. code-block:: none - - TX has 1671 zip codes - NY has 1595 zip codes - CA has 1516 zip codes - PA has 1458 zip codes - IL has 1237 zip codes - -.. seealso:: - - :phpmethod:`MongoDB\Collection::aggregate()` - -Update Documents ----------------- - -Update One Document -~~~~~~~~~~~~~~~~~~~ - -Use the :phpmethod:`MongoDB\Collection::updateOne()` method to update a single -document matching a filter. :phpmethod:`MongoDB\Collection::updateOne()` -returns a :phpclass:`MongoDB\UpdateResult` object, which you can use to access -statistics about the update operation. - -Update methods have two required parameters: the query filter that identifies -the document or documents to update, and an update document that specifies what -updates to perform. The :phpmethod:`MongoDB\Collection::updateOne()` reference -describes each parameter in detail. - -The following example inserts two documents into an empty ``users`` collection -in the ``test`` database using the :phpmethod:`MongoDB\Collection::insertOne()` -method, and then updates the documents where the value for the ``state`` field -is ``"ny"`` to include a ``country`` field set to ``"us"``: - -.. code-block:: php - - test->users; - $collection->drop(); - - $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); - $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); - $updateResult = $collection->updateOne( - ['state' => 'ny'], - ['$set' => ['country' => 'us']] - ); - - printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); - printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); - -Since the update operation uses the -:phpmethod:`MongoDB\Collection::updateOne()` method, which updates the first -document to match the filter criteria, the results would then resemble: - -.. code-block:: none - - Matched 1 document(s) - Modified 1 document(s) - -It is possible for a document to match the filter but *not be modified* by an -update, as is the case where the update sets a field's value to its existing -value, as in this example: - -.. code-block:: php - - test->users; - $collection->drop(); - - $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); - $updateResult = $collection->updateOne( - ['name' => 'Bob'], - ['$set' => ['state' => 'ny']] - ); - - printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); - printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); - -The number of matched documents and the number of *modified* documents would -therefore not be equal, and the output from the operation would resemble: - -.. code-block:: none - - Matched 1 document(s) - Modified 0 document(s) - -.. seealso:: - - - :phpmethod:`MongoDB\Collection::updateOne()` - - :phpmethod:`MongoDB\Collection::findOneAndUpdate()` - -Update Many Documents -~~~~~~~~~~~~~~~~~~~~~ - -:phpmethod:`MongoDB\Collection::updateMany()` updates one or more documents -matching the filter criteria and returns a :phpclass:`MongoDB\UpdateResult` -object, which you can use to access statistics about the update operation. - -Update methods have two required parameters: the query filter that identifies -the document or documents to update, and an update document that specifies what -updates to perform. The :phpmethod:`MongoDB\Collection::updateMany()` reference -describes each parameter in detail. - -The following example inserts three documents into an empty ``users`` collection -in the ``test`` database and then uses the :update:`$set` operator to update the -documents matching the filter criteria to include the ``country`` field with -value ``"us"``: - -.. code-block:: php - - test->users; - $collection->drop(); - - $collection->insertOne(['name' => 'Bob', 'state' => 'ny', 'country' => 'us']); - $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); - $collection->insertOne(['name' => 'Sam', 'state' => 'ny']); - $updateResult = $collection->updateMany( - ['state' => 'ny'], - ['$set' => ['country' => 'us']] - ); - - printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); - printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); - -If an update operation results in no change to a document, such as setting the -value of the field to its current value, the number of modified documents can be -less than the number of *matched* documents. Since the update document with -``name`` of ``"Bob"`` results in no changes to the document, the output of the -operation therefore resembles: - -.. code-block:: none - - Matched 3 document(s) - Modified 2 document(s) - -.. seealso:: - - :phpmethod:`MongoDB\Collection::updateMany()` - -Replace Documents -~~~~~~~~~~~~~~~~~ - -Replacement operations are similar to update operations, but instead of updating -a document to include new fields or new field values, a replacement operation -replaces the entire document with a new document, but retains the original -document's ``_id`` value. - -The :phpmethod:`MongoDB\Collection::replaceOne()` method replaces a single -document that matches the filter criteria and returns an instance of -:phpclass:`MongoDB\UpdateResult`, which you can use to access statistics about -the replacement operation. - -:phpmethod:`MongoDB\Collection::replaceOne()` has two required parameters: the -query filter that identifies the document or documents to replace, and a -replacement document that will replace the original document in MongoDB. The -:phpmethod:`MongoDB\Collection::replaceOne()` reference describes each -parameter in detail. - -.. important:: - - Replacement operations replace all of the fields in a document except the - ``_id`` value. To avoid accidentally overwriting or deleting desired fields, - use the :phpmethod:`MongoDB\Collection::updateOne()` or - :phpmethod:`MongoDB\Collection::updateMany()` methods to update individual - fields in a document rather than replacing the entire document. - -The following example inserts one document into an empty ``users`` collection in -the ``test`` database, and then replaces that document with a new one: - -.. code-block:: php - - test->users; - $collection->drop(); - - $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); - $updateResult = $collection->replaceOne( - ['name' => 'Bob'], - ['name' => 'Robert', 'state' => 'ca'] - ); - - printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); - printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); - -The output would then resemble: - -.. code-block:: none - - Matched 1 document(s) - Modified 1 document(s) - -.. seealso:: - - - :phpmethod:`MongoDB\Collection::replaceOne()` - - :phpmethod:`MongoDB\Collection::findOneAndReplace()` - -Upsert -~~~~~~ - -Update and replace operations support an :manual:`upsert -` option. When ``upsert`` is ``true`` -*and* no documents match the specified filter, the operation creates a new -document and inserts it. If there *are* matching documents, then the operation -modifies or replaces the matching document or documents. - -When a document is upserted, the ID is accessible via -:phpmethod:`MongoDB\UpdateResult::getUpsertedId()`. - -The following example uses :phpmethod:`MongoDB\Collection::updateOne()` with -the ``upsert`` option set to ``true`` and an empty ``users`` collection in the -``test`` database, therefore inserting the document into the database: - -.. code-block:: php - - test->users; - $collection->drop(); - - $updateResult = $collection->updateOne( - ['name' => 'Bob'], - ['$set' => ['state' => 'ny']], - ['upsert' => true] - ); - - printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); - printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); - printf("Upserted %d document(s)\n", $updateResult->getUpsertedCount()); - - $upsertedDocument = $collection->findOne([ - '_id' => $updateResult->getUpsertedId(), - ]); - - var_dump($upsertedDocument); - -The output would then resemble: - -.. code-block:: none - - Matched 0 document(s) - Modified 0 document(s) - Upserted 1 document(s) - object(MongoDB\Model\BSONDocument)#16 (1) { - ["storage":"ArrayObject":private]=> - array(3) { - ["_id"]=> - object(MongoDB\BSON\ObjectId)#15 (1) { - ["oid"]=> - string(24) "57509c4406d7241dad86e7c3" - } - ["name"]=> - string(3) "Bob" - ["state"]=> - string(2) "ny" - } - } - -Delete Documents ----------------- - -Delete One Document -~~~~~~~~~~~~~~~~~~~ - -The :phpmethod:`MongoDB\Collection::deleteOne()` method deletes a single -document that matches the filter criteria and returns a -:phpclass:`MongoDB\DeleteResult`, which you can use to access statistics about -the delete operation. - -If multiple documents match the filter criteria, -:phpmethod:`MongoDB\Collection::deleteOne()` deletes the :term:`first -` matching document. - -:phpmethod:`MongoDB\Collection::deleteOne()` has one required parameter: a -query filter that specifies the document to delete. Refer to the -:phpmethod:`MongoDB\Collection::deleteOne()` reference for full method -documentation. - -The following operation deletes the first document where the ``state`` field's -value is ``"ny"``: - -.. code-block:: php - - test->users; - $collection->drop(); - - $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); - $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); - $deleteResult = $collection->deleteOne(['state' => 'ny']); - - printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); - -The output would then resemble: - -.. code-block:: none - - Deleted 1 document(s) - -.. seealso:: - - :phpmethod:`MongoDB\Collection::deleteOne()` - -Delete Many Documents -~~~~~~~~~~~~~~~~~~~~~ - -:phpmethod:`MongoDB\Collection::deleteMany()` deletes all of the documents that -match the filter criteria and returns a :phpclass:`MongoDB\DeleteResult`, which -you can use to access statistics about the delete operation. - -:phpmethod:`MongoDB\Collection::deleteMany()` has one required parameter: a -query filter that specifies the document to delete. Refer to the -:phpmethod:`MongoDB\Collection::deleteMany()` reference for full method -documentation. - -The following operation deletes all of the documents where the ``state`` field's -value is ``"ny"``: - -.. code-block:: php - - test->users; - $collection->drop(); - - $collection->insertOne(['name' => 'Bob', 'state' => 'ny']); - $collection->insertOne(['name' => 'Alice', 'state' => 'ny']); - $deleteResult = $collection->deleteMany(['state' => 'ny']); - - printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); - -The output would then resemble: - -.. code-block:: none - - Deleted 2 document(s) - -.. seealso:: - - :phpmethod:`MongoDB\Collection::deleteMany()` diff --git a/source/tutorial/encryption.txt b/source/tutorial/encryption.txt index daf68155..0f1c1c1f 100644 --- a/source/tutorial/encryption.txt +++ b/source/tutorial/encryption.txt @@ -1,3 +1,5 @@ +:orphan: + ================= In-Use Encryption ================= diff --git a/source/tutorial/example-data.txt b/source/tutorial/example-data.txt deleted file mode 100644 index 30f80ff5..00000000 --- a/source/tutorial/example-data.txt +++ /dev/null @@ -1,47 +0,0 @@ -============ -Example Data -============ - -.. default-domain:: mongodb - -Some examples in this documentation use example data fixtures from -`zips.json `_ and -`primer-dataset.json `_. - -Importing the dataset into MongoDB can be done in several ways. The following -example imports the ``zips.json`` file into a ``test.zips`` collection using the -:php:`extension ` directly: - -.. code-block:: php - - toPHP(); - $bulk->insert($document); - } - - $manager = new MongoDB\Driver\Manager('mongodb://127.0.0.1/'); - - $result = $manager->executeBulkWrite('test.zips', $bulk); - printf("Inserted %d documents\n", $result->getInsertedCount()); - -The output would then resemble: - -.. code-block:: none - - Inserted 29353 documents - -You may also import the datasets using :manual:`mongoimport -`, which is included with MongoDB: - -.. code-block:: sh - - mongoimport --db test --collection zips --file zips.json --drop - mongoimport --db test --collection restaurants --file primer-dataset.json --drop diff --git a/source/tutorial/gridfs.txt b/source/tutorial/gridfs.txt deleted file mode 100644 index dc6afa15..00000000 --- a/source/tutorial/gridfs.txt +++ /dev/null @@ -1,214 +0,0 @@ -====== -GridFS -====== - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 1 - :class: singlecol - -:manual:`GridFS ` is a specification for storing and retrieving -files in MongoDB. GridFS uses two collections to store files. One collection -stores the file chunks (e.g. ``fs.chunks``), and the other stores file metadata -(e.g. ``fs.files``). The :phpclass:`MongoDB\GridFS\Bucket` class provides an -interface around these collections for working with the files as PHP -:php:`Streams `. - -Creating a GridFS Bucket ------------------------- - -You can construct a GridFS bucket using the PHP extension's -:php:`MongoDB\Driver\Manager ` class, or select -a bucket from the |php-library|'s :phpclass:`MongoDB\Database` class via the -:phpmethod:`selectGridFSBucket() ` -method. - -The bucket can be constructed with various options: - -- ``bucketName`` determines the prefix for the bucket's metadata and chunk - collections. The default value is ``"fs"``. -- ``chunkSizeBytes`` determines the size of each chunk. GridFS divides the file - into chunks of this length, except for the last, which is only as large as - needed. The default size is ``261120`` (i.e. 255 KiB). -- ``readConcern``, ``readPreference`` and ``writeConcern`` options can be used - to specify defaults for read and write operations, much like the - :phpclass:`MongoDB\Collection` options. - -Uploading Files with Writable Streams -------------------------------------- - -To upload a file to GridFS using a writable stream, you can either open a stream -and write to it directly or write the entire contents of another readable stream -to GridFS all at once. - -To open an upload stream and write to it: - -.. code-block:: php - - test->selectGridFSBucket(); - - $stream = $bucket->openUploadStream('my-file.txt'); - - $contents = file_get_contents('/path/to/my-file.txt'); - fwrite($stream, $contents); - fclose($stream); - -To upload the entire contents of a readable stream in one call: - -.. code-block:: php - - test->selectGridFSBucket(); - - $file = fopen('/path/to/my-file.txt', 'rb'); - $bucket->uploadFromStream('my-file.txt', $file); - -Downloading Files with Readable Streams ---------------------------------------- - -To download a file from GridFS using a readable stream, you can either open a -stream and read from it directly or download the entire file all at once. - -To open a download stream and read from it: - -.. code-block:: php - - test->selectGridFSBucket(); - - $stream = $bucket->openDownloadStream($fileId); - $contents = stream_get_contents($stream); - -To download the file all at once and write it to a writable stream: - -.. code-block:: php - - test->selectGridFSBucket(); - - $file = fopen('/path/to/my-output-file.txt', 'wb'); - - $bucket->downloadToStream($fileId, $file); - -Selecting Files by Filename and Revision ----------------------------------------- - -You can also download a file specified by filename and (optionally) revision -number. Revision numbers are used to distinguish between files sharing the same -``filename`` metadata field, ordered by date of upload (i.e. the ``uploadDate`` -metadata field). The ``revision`` option accepted by -:phpmethod:`openDownloadStreamByName() -` and -:phpmethod:`downloadToStreamByName() -` can be positive or negative. - -A positive ``revision`` number may be used to select files in order of the -oldest upload date. A revision of ``0`` would denote the file with the oldest -upload date, a revision of ``1`` would denote the second oldest upload, and so -on. - -A negative revision may be used to select files in order of the most recent -upload date. A revision of ``-1`` would denote a file with the most recent -upload date, a revision of ``-2`` would denote the second most recent upload, -and so on. The ``revision`` option defaults to ``-1`` if not specified. - -The following example downloads the contents of the oldest version of a -particular file: - -.. code-block:: php - - test->selectGridFSBucket(); - - $stream = $bucket->openDownloadStreamByName('my-file.txt', ['revision' => 0]); - $contents = stream_get_contents($stream); - -Deleting Files --------------- - -You can delete a GridFS file by its ``_id``. - -.. code-block:: php - - test->selectGridFSBucket(); - - $bucket->delete($fileId); - -Finding File Metadata ---------------------- - -The :phpmethod:`find() ` method allows you to -retrieve documents from the GridFS files collection, which contain metadata -about the GridFS files. - -.. code-block:: php - - test->selectGridFSBucket(); - - $cursor = $bucket->find(['filename' => 'my-file.txt']); - -Accessing File Metadata for an Existing Stream ----------------------------------------------- - -The :phpmethod:`getFileDocumentForStream() -` method may be used to get -the file document for an existing readable or writable GridFS stream. - -.. code-block:: php - - test->selectGridFSBucket(); - - $stream = $bucket->openDownloadStream($fileId); - $metadata = $bucket->getFileDocumentForStream($stream); - -.. note:: - - Since the file document for a writable stream is not committed to MongoDB - until the stream is closed, - :phpmethod:`getFileDocumentForStream() - ` can only return an - in-memory document, which will be missing some fields (e.g. ``length``, - ``md5``). - -The :phpmethod:`getFileIdForStream() -` method may be used to get the -``_id`` for an existing readable or writable GridFS stream. This is a -convenience for accessing the ``_id`` property of the object returned by -:phpmethod:`getFileDocumentForStream() -`. - -.. code-block:: php - - test->selectGridFSBucket(); - - $stream = $bucket->openDownloadStreamByName('my-file.txt'); - $fileId = $bucket->getFileIdForStream($stream); diff --git a/source/tutorial/indexes.txt b/source/tutorial/indexes.txt deleted file mode 100644 index 51d2d3f7..00000000 --- a/source/tutorial/indexes.txt +++ /dev/null @@ -1,139 +0,0 @@ -======= -Indexes -======= - -.. default-domain:: mongodb - -Indexes support the efficient execution of queries in MongoDB. Without indexes, -MongoDB must perform a *collection scan*, i.e. scan every document in a -collection, to select those documents that match the query statement. If an -appropriate index exists for a query, MongoDB can use the index to limit the -number of documents it must inspect. - -The PHP driver supports managing indexes through the -:phpclass:`MongoDB\Collection` class, which implements MongoDB's -cross-driver `Index Management -`_ -and `Enumerating Indexes -`_ -specifications. - -This document provides an introduction to creating, listing, and dropping -indexes using the |php-library|. The MongoDB Manual's :manual:`Indexes -` reference provides more thorough information about indexing in -MongoDB. - -Create Indexes --------------- - -Create indexes with the :phpmethod:`MongoDB\Collection::createIndex()` or -:phpmethod:`MongoDB\Collection::createIndexes()` methods. Refer to the method -reference for more details about each method. - -The following example creates an ascending index on the ``state`` field using -the :phpmethod:`createIndex() ` method: - -.. code-block:: php - - test->zips; - - $result = $collection->createIndex(['state' => 1]); - - var_dump($result); - -When you create an index, the method returns its name, which is automatically -generated from its specification. The above example would output something -similar to: - -.. code-block:: none - - string(7) "state_1" - -List Indexes ------------- - -The :phpmethod:`MongoDB\Collection::listIndexes()` method provides information -about the indexes in a collection. The -:phpmethod:`MongoDB\Collection::listIndexes()` method returns an iterator of -:phpclass:`MongoDB\Model\IndexInfo` objects, which you can use to view -information about each index. Refer to the method reference for more details. - -The following example lists all indexes in the ``zips`` collection in the -``test`` database: - -.. code-block:: php - - test->zips; - - foreach ($collection->listIndexes() as $indexInfo) { - var_dump($indexInfo); - } - -The output would resemble: - -.. code-block:: none - - object(MongoDB\Model\IndexInfo)#10 (4) { - ["v"]=> - int(1) - ["key"]=> - array(1) { - ["_id"]=> - int(1) - } - ["name"]=> - string(4) "_id_" - ["ns"]=> - string(9) "test.zips" - } - object(MongoDB\Model\IndexInfo)#13 (4) { - ["v"]=> - int(1) - ["key"]=> - array(1) { - ["state"]=> - int(1) - } - ["name"]=> - string(7) "state_1" - ["ns"]=> - string(9) "test.zips" - } - -Drop Indexes ------------- - -The :phpmethod:`MongoDB\Collection::dropIndex()` method lets you drop a single -index while :phpmethod:`MongoDB\Collection::dropIndexes()` drops all of the -indexes on a collection. Refer to the method reference for more details about -each method. - -The following example drops a single index by its name, ``state_1``: - -.. code-block:: php - - test->zips; - - $result = $collection->dropIndex('state_1'); - - var_dump($result); - -The operation's output would resemble: - -.. code-block:: none - - object(MongoDB\Model\BSONDocument)#11 (1) { - ["storage":"ArrayObject":private]=> - array(2) { - ["nIndexesWas"]=> - int(2) - ["ok"]=> - float(1) - } - } diff --git a/source/tutorial/server-selection.txt b/source/tutorial/server-selection.txt index c63ca5c9..0710de7c 100644 --- a/source/tutorial/server-selection.txt +++ b/source/tutorial/server-selection.txt @@ -1,3 +1,5 @@ +:orphan: + =============================== Server Selection and Monitoring =============================== diff --git a/source/tutorial/stable-api.txt b/source/tutorial/stable-api.txt deleted file mode 100644 index d018162a..00000000 --- a/source/tutorial/stable-api.txt +++ /dev/null @@ -1,93 +0,0 @@ -========== -Stable API -========== - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 1 - :class: singlecol - -Declaring an API Version ------------------------- - -To declare an API version, pass a ``serverApi`` driver option when creating your -client. The value is a -:php:`MongoDB\Driver\ServerApi ` instance that -contains API version information. This feature is introduced in MongoDB 5.0, -which will initially support only API version "1". Additional versions may be -introduced in future versions of the server. - -.. code-block:: php - - $serverApi]); - - // Command includes the declared API version - $client->database->collection->find([]); - -.. note:: - - Only declare an API version when connecting to a deployment that has no - pre-5.0 members. Older servers will error when encountering commands with a - declared API version. - -Strict API ----------- - -By default, declaring an API version guarantees behavior for commands that are -part of the stable API, but does not forbid using commands that are not part -of the API version. To only allow commands and options that are part of the -stable API, specify the ``strict`` option when creating the -:php:`MongoDB\Driver\ServerApi ` instance: - -.. code-block:: php - - $serverApi]); - - // Will fail as the tailable option is not supported in versioned API - $client->database->collection->find([], ['tailable' => true]); - -Fail on Deprecated Commands ---------------------------- - -The optional ``deprecationErrors`` option causes MongoDB to fail all commands -or behaviors that have been deprecated in the API version. This can be used in -testing to ensure a smooth transition to a future API version. - -.. code-block:: php - - $serverApi]); - -.. note:: - - At the time of this writing, no part of API version "1" has been deprecated. - -Usage with the Command Helper ------------------------------ - -When using the :phpmethod:`MongoDB\Database::command()` method to run arbitrary -commands, the API version declared to the client is automatically appended to -the command document. Setting any of the ``apiVersion``, ``apiStrict``, or -``apiDeprecationErrors`` command options in the command document and calling -:phpmethod:`MongoDB\Database::command()` from a client with a declared API -version is not supported and will lead to undefined behavior. diff --git a/source/tutorial/tailable-cursor.txt b/source/tutorial/tailable-cursor.txt deleted file mode 100644 index 6285676e..00000000 --- a/source/tutorial/tailable-cursor.txt +++ /dev/null @@ -1,190 +0,0 @@ -.. _php-tailable-cursor: - -========================= -Tailable Cursor Iteration -========================= - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Overview --------- - -When the driver executes a query or command (e.g. -:manual:`aggregate `), results from the operation -are returned via a :php:`MongoDB\Driver\Cursor ` -object. The Cursor class implements PHP's :php:`Iterator ` -interface, which allows it to be iterated with ``foreach`` and interface with -any PHP functions that work with :php:`iterables `. Similar to -result objects in other database drivers, cursors in MongoDB only support -forward iteration, which means they cannot be rewound or used with ``foreach`` -multiple times. - -:manual:`Tailable cursors ` are a special type of -MongoDB cursor that allows the client to read some results and then wait until -more documents become available. These cursors are primarily used with -:manual:`Capped Collections ` and -:manual:`Change Streams `. - -While normal cursors can be iterated once with ``foreach``, that approach will -not work with tailable cursors. When ``foreach`` is used with a tailable cursor, -the loop will stop upon reaching the end of the initial result set. Attempting -to continue iteration on the cursor with a second ``foreach`` would throw an -exception, since PHP attempts to rewind the cursor. Therefore, reading from a -tailable cursor will require direct usage of the :php:`Iterator ` API. - -.. note:: - - Before version 1.9.0 of the ``ext-mongodb`` extension, the cursor class does - not implement the :php:`Iterator ` interface. To manually iterate - a cursor using the method below, it must first be wrapped with an - :php:`IteratorIterator `. - -Manually Iterating a Normal Cursor ----------------------------------- - -Before looking at how a tailable cursor can be iterated, we'll start by -examining how the ``Iterator`` methods interact with a normal cursor. - -The following example finds five restaurants and uses ``foreach`` to view the -results: - -.. code-block:: php - - test->restaurants; - - $cursor = $collection->find([], ['limit' => 5]); - - foreach ($cursor as $document) { - var_dump($document); - } - -While this example is quite concise, there is actually quite a bit going on. The -``foreach`` construct begins by rewinding the iterable (``$cursor`` in this -case). It then checks if the current position is valid. If the position is not -valid, the loop ends. Otherwise, the current key and value are accessed -accordingly and the loop body is executed. Assuming a :php:`break ` has -not occurred, the iterator then advances to the next position, control jumps -back to the validity check, and the loop continues. - -With the inner workings of ``foreach`` under our belt, we can now translate the -preceding example to use the Iterator methods directly: - -.. code-block:: php - - test->restaurants; - - $cursor = $collection->find([], ['limit' => 5]); - - $cursor->rewind(); - - while ($cursor->valid()) { - $document = $cursor->current(); - var_dump($document); - $cursor->next(); - } - -.. note:: - - Calling ``$cursor->next()`` after the ``while`` loop naturally ends would - throw an exception, since all results on the cursor have been exhausted. - -The purpose of this example is to demonstrate the functional equivalence between -``foreach`` and manual iteration with PHP's :php:`Iterator ` API. -For normal cursors, there is little reason to manually iterate results instead -of a concise ``foreach`` loop. - -Iterating a Tailable Cursor ---------------------------- - -In order to demonstrate a tailable cursor in action, we'll need two scripts: a -"producer" and a "consumer". The producer script will create a new capped -collection using :phpmethod:`MongoDB\Database::createCollection()` and proceed -to insert a new document into that collection each second. - -.. code-block:: php - - test; - - $database->createCollection('capped', [ - 'capped' => true, - 'size' => 16777216, - ]); - - $collection = $database->selectCollection('capped'); - - while (true) { - $collection->insertOne(['createdAt' => new MongoDB\BSON\UTCDateTime()]); - sleep(1); - } - -With the producer script still running, we will now execute a consumer script to -read the inserted documents using a tailable cursor, indicated by the -``cursorType`` option to :phpmethod:`MongoDB\Collection::find()`. We'll start -by using ``foreach`` to illustrate its shortcomings: - -.. code-block:: php - - test->capped; - - $cursor = $collection->find([], [ - 'cursorType' => MongoDB\Operation\Find::TAILABLE_AWAIT, - 'maxAwaitTimeMS' => 100, - ]); - - foreach ($cursor as $document) { - printf("Consumed document created at: %s\n", $document->createdAt); - } - -If you execute this consumer script, you'll notice that it quickly exhausts all -results in the capped collection and then terminates. We cannot add a second -``foreach``, as that would throw an exception when attempting to rewind the -cursor. This is a ripe use case for directly controlling the iteration process -using the :php:`Iterator ` interface. - -.. code-block:: php - - test->capped; - - $cursor = $collection->find([], [ - 'cursorType' => MongoDB\Operation\Find::TAILABLE_AWAIT, - 'maxAwaitTimeMS' => 100, - ]); - - $cursor->rewind(); - - while (true) { - if ($cursor->valid()) { - $document = $cursor->current(); - printf("Consumed document created at: %s\n", $document->createdAt); - } - - $cursor->next(); - } - -Much like the ``foreach`` example, this version on the consumer script will -start by quickly printing all results in the capped collection; however, it will -not terminate upon reaching the end of the initial result set. Since we're -working with a tailable cursor, calling ``next()`` will block and wait for -additional results rather than throw an exception. We will also use ``valid()`` -to check if there is actually data available to read at each step. - -Since we've elected to use a ``TAILABLE_AWAIT`` cursor, the server will delay -its response to the driver for a set amount of time. In this example, we've -requested that the server block for approximately 100 milliseconds by specifying -the ``maxAwaitTimeMS`` option to :phpmethod:`MongoDB\Collection::find()`. diff --git a/source/upgrade.txt b/source/upgrade.txt deleted file mode 100644 index 18e92e52..00000000 --- a/source/upgrade.txt +++ /dev/null @@ -1,369 +0,0 @@ -=========================== -Legacy Driver Upgrade Guide -=========================== - -.. default-domain:: mongodb - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Overview --------- - -The |php-library| and underlying :php:`mongodb extension ` have notable -API differences from the legacy ``mongo`` extension. This page will summarize -those differences for the benefit of those upgrading from the legacy driver. - -Additionally, a community-developed `mongo-php-adapter -`_ library exists, which -implements the ``mongo`` extension API using this library and the ``mongodb`` -extension. While this adapter library is not officially supported by MongoDB, it -does bear mentioning. - -BSON ----- - -Type Classes -~~~~~~~~~~~~ - -When upgrading from the legacy driver, type classes such as MongoId must be -replaced with classes in the -`MongoDB\\BSON namespace `_. The new -driver also introduces interfaces for its BSON types, which should be preferred -if applications need to type hint against BSON values. - -The following table lists all legacy classes alongside the equivalent class in -the new driver. - -.. list-table:: - :header-rows: 1 - - * - Legacy class - - BSON type class - - BSON type interface - - * - MongoId - - :php:`MongoDB\BSON\ObjectId ` - - :php:`MongoDB\BSON\ObjectIdInterface ` - - * - MongoCode - - :php:`MongoDB\BSON\Javascript ` - - :php:`MongoDB\BSON\JavascriptInterface ` - - * - MongoDate - - :php:`MongoDB\BSON\UTCDateTime ` - - :php:`MongoDB\BSON\UTCDateTimeInterface ` - - * - MongoRegex - - :php:`MongoDB\BSON\Regex ` - - :php:`MongoDB\BSON\RegexInterface ` - - * - MongoBinData - - :php:`MongoDB\BSON\Binary ` - - :php:`MongoDB\BSON\BinaryInterface ` - - * - MongoInt32 - - Not implemented. [1]_ - - - - * - MongoInt64 - - :php:`MongoDB\BSON\Int64 ` - - Not implemented. [2]_ - - * - MongoDBRef - - Not implemented. [3]_ - - - - * - MongoMinKey - - :php:`MongoDB\BSON\MinKey ` - - :php:`MongoDB\BSON\MinKeyInterface ` - - * - MongoMaxKey - - :php:`MongoDB\BSON\MaxKey ` - - :php:`MongoDB\BSON\MaxKeyInterface ` - - * - MongoTimestamp - - :php:`MongoDB\BSON\Timestamp ` - - :php:`MongoDB\BSON\TimestampInterface ` - -.. [1] The new driver does not implement an equivalent class for MongoInt32. - When decoding BSON, 32-bit integers will always be represented as a PHP - integer. When encoding BSON, PHP integers will encode as either a 32-bit or - 64-bit integer depending on their value. - -.. [2] :php:`MongoDB\BSON\Int64 ` does not have an - interface defined. - -.. [3] The new driver does not implement an equivalent class for MongoDBRef - since :manual:`DBRefs ` are merely a BSON - document with a particular structure and not a proper BSON type. The new - driver also does not provide any helpers for working with DBRef objects, - since their use is not encouraged. - -Emulating the Legacy Driver -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The legacy ``mongo`` extension returned both BSON documents and arrays as PHP -arrays. While PHP arrays are convenient to work with, this behavior was -problematic: - -- Different BSON types could deserialize to the same PHP value (e.g. - ``{"0": "foo"}`` and ``["foo"]``), which made it impossible to infer the - original BSON type. - -- Numerically-indexed PHP arrays would be serialized as BSON documents if there - was a gap in their key sequence. Such gaps were caused by unsetting a key to - remove an element and forgetting to numerically reindex the array. - -The |php-library|'s :phpclass:`BSONDocument ` and -:phpclass:`BSONArray ` classes address these concerns -by preserving the BSON type information during serialization and -deserialization; however, some users may still prefer the legacy behavior. If -desired, you can use the ``typeMap`` option to have the library return -everything as a PHP array: - -.. code-block:: php - - [ - 'array' => 'array', - 'document' => 'array', - 'root' => 'array', - ], - ] - ); - - $document = $client->test->zips->findOne(['_id' => '94301']); - - var_dump($document); - -The above example would output something similar to: - -.. code-block:: php - - array(5) { - ["_id"]=> - string(5) "94301" - ["city"]=> - string(9) "PALO ALTO" - ["loc"]=> - array(2) { - [0]=> - float(-122.149685) - [1]=> - float(37.444324) - } - ["pop"]=> - int(15965) - ["state"]=> - string(2) "CA" - } - -Collection API --------------- - -This library's :phpclass:`MongoDB\Collection` class implements MongoDB's -cross-driver `CRUD -`_ -and `Index Management -`_ -specifications. Although some method names have changed in accordance with the -new specifications, the new class provides the same functionality as the legacy -driver's MongoCollection class with some notable exceptions. - -A guiding principle in designing the new APIs was that explicit method names are -preferable to overloaded terms found in the old API. For instance, -``MongoCollection::save()`` and ``MongoCollection::findAndModify()`` have -different modes of operation, depending on their arguments. Methods were also -split to distinguish between :manual:`updating specific fields -` and :manual:`full-document replacement -`. - -The following table lists all legacy methods alongside the -equivalent method(s) in the new driver. - -.. list-table:: - :header-rows: 1 - - * - MongoCollection method - - :phpclass:`MongoDB\Collection` method(s) - - * - ``MongoCollection::aggregate()`` - - :phpmethod:`MongoDB\Collection::aggregate()` - - * - ``MongoCollection::aggregateCursor()`` - - :phpmethod:`MongoDB\Collection::aggregate()` - - * - ``MongoCollection::batchInsert()`` - - :phpmethod:`MongoDB\Collection::insertMany()` - - * - ``MongoCollection::count()`` - - :phpmethod:`MongoDB\Collection::count()` - - * - ``MongoCollection::createDBRef()`` - - Not yet implemented. [3]_ - - * - ``MongoCollection::createIndex()`` - - :phpmethod:`MongoDB\Collection::createIndex()` - - * - ``MongoCollection::deleteIndex()`` - - :phpmethod:`MongoDB\Collection::dropIndex()` - - * - ``MongoCollection::deleteIndexes()`` - - :phpmethod:`MongoDB\Collection::dropIndexes()` - - * - ``MongoCollection::drop()`` - - :phpmethod:`MongoDB\Collection::drop()` - - * - ``MongoCollection::distinct()`` - - :phpmethod:`MongoDB\Collection::distinct()` - - * - ``MongoCollection::ensureIndex()`` - - :phpmethod:`MongoDB\Collection::createIndex()` - - * - ``MongoCollection::find()`` - - :phpmethod:`MongoDB\Collection::find()` - - * - ``MongoCollection::findAndModify()`` - - :phpmethod:`MongoDB\Collection::findOneAndDelete()`, - :phpmethod:`MongoDB\Collection::findOneAndReplace()`, and - :phpmethod:`MongoDB\Collection::findOneAndUpdate()` - - * - ``MongoCollection::findOne()`` - - :phpmethod:`MongoDB\Collection::findOne()` - - * - ``MongoCollection::getDBRef()`` - - Not implemented. [3]_ - - * - ``MongoCollection::getIndexInfo()`` - - :phpmethod:`MongoDB\Collection::listIndexes()` - - * - ``MongoCollection::getName()`` - - :phpmethod:`MongoDB\Collection::getCollectionName()` - - * - ``MongoCollection::getReadPreference()`` - - :phpmethod:`MongoDB\Collection::getReadPreference()` - - * - ``MongoCollection::getSlaveOkay()`` - - Not implemented. - - * - ``MongoCollection::getWriteConcern()`` - - :phpmethod:`MongoDB\Collection::getWriteConcern()` - - * - ``MongoCollection::group()`` - - Not implemented. Use :phpmethod:`MongoDB\Database::command()`. See - :ref:`Group Command Helper ` for an example. - - * - ``MongoCollection::insert()`` - - :phpmethod:`MongoDB\Collection::insertOne()` - - * - ``MongoCollection::parallelCollectionScan()`` - - Not implemented. - - * - ``MongoCollection::remove()`` - - :phpmethod:`MongoDB\Collection::deleteMany()` and - :phpmethod:`MongoDB\Collection::deleteOne()` - - * - ``MongoCollection::save()`` - - :phpmethod:`MongoDB\Collection::insertOne()` or - :phpmethod:`MongoDB\Collection::replaceOne()` with the ``upsert`` - option. - - * - ``MongoCollection::setReadPreference()`` - - Not implemented. Use :phpmethod:`MongoDB\Collection::withOptions()`. - - * - ``MongoCollection::setSlaveOkay()`` - - Not implemented. - - * - ``MongoCollection::setWriteConcern()`` - - Not implemented. Use :phpmethod:`MongoDB\Collection::withOptions()`. - - * - ``MongoCollection::update()`` - - :phpmethod:`MongoDB\Collection::replaceOne()`, - :phpmethod:`MongoDB\Collection::updateMany()`, and - :phpmethod:`MongoDB\Collection::updateOne()`. - - * - ``MongoCollection::validate()`` - - Not implemented. - -Accessing IDs of Inserted Documents -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In the legacy driver, ``MongoCollection::insert()``, -``MongoCollection::batchInsert()``, and ``MongoCollection::save()`` (when -inserting) would modify their input argument by injecting an ``_id`` key with a -generated ObjectId (i.e. MongoId object). This behavior was a bit of a hack, as -it did not rely on the argument being :php:`passed by reference -`; instead, it directly modified memory through the -extension API and could not be implemented in PHP userland. As such, it is no -longer done in the new driver. - -IDs of inserted documents (whether generated or not) may be accessed through the -following methods on the write result objects: - -- :phpmethod:`MongoDB\InsertOneResult::getInsertedId()` for - :phpmethod:`MongoDB\Collection::insertOne()` -- :phpmethod:`MongoDB\InsertManyResult::getInsertedIds()` for - :phpmethod:`MongoDB\Collection::insertMany()` -- :phpmethod:`MongoDB\BulkWriteResult::getInsertedIds()` for - :phpmethod:`MongoDB\Collection::bulkWrite()` - -Bulk Write Operations -~~~~~~~~~~~~~~~~~~~~~ - -The legacy driver's MongoWriteBatch classes have been replaced with a -general-purpose :phpmethod:`MongoDB\Collection::bulkWrite()` method. Whereas -the legacy driver only allowed bulk operations of the same type, the new method -allows operations to be mixed (e.g. inserts, updates, and deletes). - -MongoCollection::save() Removed -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``MongoCollection::save()``, which was syntactic sugar for an insert or upsert -operation, has been removed in favor of explicitly using -:phpmethod:`MongoDB\Collection::insertOne()` or -:phpmethod:`MongoDB\Collection::replaceOne()` (with the ``upsert`` option). - -While the ``save`` method does have its uses for interactive environments, such -as the MongoDB shell, it was intentionally excluded from the -`CRUD specification `_ -for language drivers. Generally, application code should know if the document -has an identifier and be able to explicitly insert or replace the document and -handle the returned :phpclass:`MongoDB\InsertOneResult` or -:phpclass:`MongoDB\UpdateResult`, respectively. This also helps avoid -inadvertent and potentially dangerous :manual:`full-document replacements -`. - -.. _group-command-helper: - -Group Command Helper -~~~~~~~~~~~~~~~~~~~~ - -:phpclass:`MongoDB\Collection` does not have a helper method for the -:manual:`group ` command. The following example -demonstrates how to execute a group command using the -:phpmethod:`MongoDB\Database::command()` method: - -.. code-block:: php - - selectDatabase('db_name'); - $cursor = $database->command([ - 'group' => [ - 'ns' => 'collection_name', - 'key' => ['field_name' => 1], - 'initial' => ['total' => 0], - '$reduce' => new MongoDB\BSON\Javascript('...'), - ], - ]); - - $resultDocument = $cursor->toArray()[0]; From e236d7ab24e5fc124b1b81c97674ef72e8c8de1b Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 13:09:24 -0400 Subject: [PATCH 098/149] edit sample app intro --- source/includes/usage-examples/sample-app-intro.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/includes/usage-examples/sample-app-intro.rst b/source/includes/usage-examples/sample-app-intro.rst index cee5f2d7..a17549fe 100644 --- a/source/includes/usage-examples/sample-app-intro.rst +++ b/source/includes/usage-examples/sample-app-intro.rst @@ -4,7 +4,9 @@ Sample Application You can use the following sample application to test the code examples on this page. To use the sample application, perform the following steps: -1. Ensure you have the {+php-library+} installed in your project. +1. Ensure you have the {+php-library+} installed in your project. To learn more + about installing the {+php-library+}, see the + :ref:`Download and Install ` guide. #. Copy the following code and paste it into a new ``.php`` file. #. Copy a code example from this page and paste it on the specified lines in the file. From ac0e57d1470a122190db0f1dc77e78673bc1fe52 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 13:18:27 -0400 Subject: [PATCH 099/149] change links in count sections --- source/read.txt | 4 ++-- source/read/count.txt | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/source/read.txt b/source/read.txt index 2af56092..69728dd9 100644 --- a/source/read.txt +++ b/source/read.txt @@ -100,7 +100,7 @@ a collection: :dedent: To learn more about the ``countDocuments()`` method, see the -:ref:`php-accurate-count` section in the Count Documents guide. +:ref:`php-count-all` section in the Count Documents guide. Count Documents Returned from a Query ------------------------------------- @@ -115,7 +115,7 @@ that match the specified criteria: :dedent: To learn more about the ``countDocuments()`` method, see the -:ref:`php-accurate-count` section in the Count Documents guide. +:ref:`php-count-specific` section in the Count Documents guide. Estimated Document Count ------------------------ diff --git a/source/read/count.txt b/source/read/count.txt index 5b825a78..d4516602 100644 --- a/source/read/count.txt +++ b/source/read/count.txt @@ -58,6 +58,8 @@ pass a query filter to the ``countDocuments()`` method. To learn more about specifying a query, see the :ref:`php-specify-query` guide. +.. _php-count-all: + Count All Documents ~~~~~~~~~~~~~~~~~~~ @@ -78,6 +80,8 @@ the ``countDocuments()`` method, as shown in the following example: Number of documents: 9500 +.. _php-count-specific: + Count Specific Documents ~~~~~~~~~~~~~~~~~~~~~~~~ From 23738fde94b2abe39e96b4fc60fa07aafc4186e5 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 14:09:34 -0400 Subject: [PATCH 100/149] update sample app intro --- source/read.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/read.txt b/source/read.txt index 69728dd9..edc62a13 100644 --- a/source/read.txt +++ b/source/read.txt @@ -43,9 +43,11 @@ On this page, you can see copyable code examples that show common provided in each section. To use an example from this page, copy the code example into the -:ref:`sample application ` or your own application. -Be sure to replace all placeholders, such as ````, with -the relevant values for your MongoDB deployment. +:ref:`sample application ` or your own application. +Make sure to set the ``MONGODB_URI`` environment variable to the +connection string for your MongoDB deployment, and replace the +```` and ```` placeholders with values for your +target namespace. .. _php-read-sample: From 3bb2cb714fb7869cbc7291ae60340a801cacb0ac Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Wed, 25 Sep 2024 15:23:46 -0400 Subject: [PATCH 101/149] DOCSP-41990: Authentication mechanisms (#139) * DOCSP-41990: Authentication mechanisms * client tabs * edits * edits * add info * reduce repetition * add section * fix link * MW feedback * fix * JM most feedback * move to code file * more JM edits * JM feedback 2 --- source/includes/authentication.php | 70 ++++++ source/security.txt | 3 +- source/security/authentication.txt | 390 +++++++++++++++++++++++++++++ 3 files changed, 462 insertions(+), 1 deletion(-) create mode 100644 source/includes/authentication.php create mode 100644 source/security/authentication.txt diff --git a/source/includes/authentication.php b/source/includes/authentication.php new file mode 100644 index 00000000..58557aca --- /dev/null +++ b/source/includes/authentication.php @@ -0,0 +1,70 @@ + '', + 'password' => '', + 'authSource' => '', + 'authMechanism' => 'SCRAM-SHA-256', +]; + +$client = new MongoDB\Client( + 'mongodb://:', + $uriOptions, +); +// end-scram-sha-256-client + +// start-scram-sha-256-uri +$uri = 'mongodb://:@:/?authSource=admin&authMechanism=SCRAM-SHA-256'; +$client = new MongoDB\Client($uri); +// end-scram-sha-256-uri + +// start-mongodb-X509-client +$uriOptions = [ + 'tls' => true, + 'tlsCertificateKeyFile' => '', + 'authMechanism' => 'MONGODB-X509', +]; + +$client = new MongoDB\Client( + 'mongodb://:', + $uriOptions, +); +// end-mongodb-X509-client + +// start-mongodb-X509-uri +$uri = 'mongodb://:/?tls=true&tlsCertificateKeyFile=&authMechanism=MONGODB-X509'; +$client = new MongoDB\Client($uri); +// end-mongodb-X509-uri + +// start-mongodb-aws-client +$uriOptions = [ + 'username' => '', + 'password' => '', + 'authMechanism' => 'MONGODB-AWS', +]; + +$client = new MongoDB\Client( + 'mongodb://:', + $uriOptions, +); +// end-mongodb-aws-client + +// start-mongodb-aws-uri +$uri = 'mongodb://:@:/?authMechanism=MONGODB-AWS'; +$client = new MongoDB\Client($uri); +// end-mongodb-aws-uri + +// start-mongodb-aws-env-client +$client = new MongoDB\Client( + 'mongodb://:', + ['authMechanism' => 'MONGODB-AWS'] +); +// end-mongodb-aws-env-client + +// start-mongodb-aws-env-uri +$uri = 'mongodb://:/?authMechanism=MONGODB-AWS'; +$client = new MongoDB\Client($uri); +// end-mongodb-aws-env-uri diff --git a/source/security.txt b/source/security.txt index 2e581856..b70e1a59 100644 --- a/source/security.txt +++ b/source/security.txt @@ -8,4 +8,5 @@ Secure Your Data :titlesonly: :maxdepth: 1 - /security/in-use-encryption \ No newline at end of file + /security/authentication + /security/in-use-encryption diff --git a/source/security/authentication.txt b/source/security/authentication.txt new file mode 100644 index 00000000..13050e19 --- /dev/null +++ b/source/security/authentication.txt @@ -0,0 +1,390 @@ +.. _php-auth: + +========================= +Authentication Mechanisms +========================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: authorize, secure, connect, code example + +Overview +-------- + +This guide describes the mechanisms you can use in the {+driver-short+} to authenticate +users. + +.. important:: Percent-Encoding + + You must :wikipedia:`percent-encode ` a username and password before + you include them in a MongoDB URI. You can use the ``rawurlencode()`` method to encode + these values according to the URI syntax specified in RFC 3986. Don't percent-encode the + username or password when passing them in an options array parameter to the ``MongoDB\Client`` + constructor. + + To learn more, see the following resources: + + - `RFC 3986 `__ + - `rawurlencode <{+php-manual+}/rawurlencode>`__ in the PHP manual + +.. _php-scram-sha-256: + +SCRAM-SHA-256 +------------- + +SCRAM-SHA-256, as defined by `RFC 7677 `__, +is the default authentication mechanism on MongoDB deployments +running {+mdb-server+} v4.0 or later. + +To authenticate with this mechanism, set the following connection options: + +- ``username``: The username to authenticate. Percent-encode this value before including + it in a connection URI. +- ``password``: The password to authenticate. Percent-encode this value before including + it in a connection URI. +- ``authSource``: The MongoDB database to authenticate against. By default, the + {+php-library+} authenticates against the database in the connection + URI, if you include one. If you don't, it authenticates against the ``admin`` database. +- ``authMechanism``: Set to ``'SCRAM-SHA-256'``. When connected to {+mdb-server+} v4.0, + setting ``authMechanism`` is optional. + +You can set these options in two ways: by passing an options array to the +``MongoDB\Client`` constructor or through parameters in your connection URI. + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-scram-sha-256-client + :end-before: end-scram-sha-256-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-scram-sha-256-uri + :end-before: end-scram-sha-256-uri + +.. _php-scram-sha-1: + +SCRAM-SHA-1 +----------- + +SCRAM-SHA-1, as defined by `RFC 5802 `__, +is the default authentication mechanism on MongoDB deployments +running {+mdb-server+} v3.6. + +.. note:: + + {+php-library+} v1.20 drops support for {+mdb-server+} v3.6. When using v1.20+ of + the library, all supported server versions default to the SCRAM-SHA-256 authentication + mechanism. + +To authenticate with this mechanism, use the same syntax as the :ref:`php-scram-sha-256`, +but change the value of the ``authMechanism`` option to ``'SCRAM-SHA-1'``. + +.. _php-mongodb-x509: + +MONGODB-X509 +------------ + +If you enable TLS, during the TLS handshake, the {+php-library+} can present an X.509 +client certificate to MongoDB to prove its identity. The MONGODB-X509 authentication +mechanism uses this certificate to authenticate the client. + +To authenticate with this mechanism, set the following connection options: + +- ``tls``: Set to ``true``. +- ``tlsCertificateKeyFile``: The file path of the ``.pem`` file that contains your + client certificate and private key. +- ``authMechanism``: Set to ``'MONGODB-X509'``. + +You can set these options in two ways: by passing an options array to the +``MongoDB\Client`` constructor or through parameters in your connection URI. + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-X509-client + :end-before: end-mongodb-X509-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-X509-uri + :end-before: end-mongodb-X509-uri + +.. _php-mongodb-aws: + +MONGODB-AWS +----------- + +.. important:: + + The MONGODB-AWS authentication mechanism requires {+mdb-server+} v4.4 or later. + +The MONGODB-AWS authentication mechanism uses AWS IAM (Amazon Web Services Identity and +Access Management) or AWS Lambda credentials to authenticate your application. To use this +method to authenticate, you must specify ``'MONGODB-AWS'`` as the value of +the ``authMechanism`` connection option. + +.. note:: + + The {+php-library+} uses libmongoc's implementation of the MONGODB-AWS + authentication mechanism. To learn more about using this authentication mechanism + with libmongoc, see `Authentication via AWS IAM + `__ + in the C driver documentation. + +When you use the MONGODB-AWS mechanism, the driver tries to retrieve AWS +credentials from the following sources, in the order listed: + +1. Options passed to the ``MongoDB\Client`` either as part of the connection + URI or an options parameter +#. Environment variables +#. AWS EKS ``AssumeRoleWithWebIdentity`` request +#. ECS container metadata +#. EC2 instance metadata + +The following sections describe how to retrieve credentials from +these sources and use them to authenticate your PHP application. + +.. _php-mongodb-aws-credentials: + +MongoDB\Client Credentials +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +First, the driver checks whether you passed AWS credentials to the +``MongoDB\Client`` constructor, either as as part of the connection +URI or the ``$uriOptions`` array parameter. To pass your credentials to +``MongoDB\Client``, set the following connection options: + +- ``username``: The AWS IAM access key ID to authenticate. Percent-encode this value + before including it in a connection URI. +- ``password``: The AWS IAM secret access key. Percent-encode this value before including + it in a connection URI. +- ``authMechanism``: Set to ``'MONGODB-AWS'``. + +You can set these options in two ways: by passing an options array to the +``MongoDB\Client`` constructor or through parameters in your connection URI. + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-aws-client + :end-before: end-mongodb-aws-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-aws-uri + :end-before: end-mongodb-aws-uri + +.. _php-mongodb-aws-env-vars: + +Environment Variables +~~~~~~~~~~~~~~~~~~~~~ + +If you don't provide a username and password when you construct your ``MongoDB\Client`` +object, the driver tries to retrieve AWS credentials from the following +environment variables: + +- ``AWS_ACCESS_KEY_ID`` +- ``AWS_SECRET_ACCESS_KEY`` +- ``AWS_SESSION_TOKEN`` + +To use these environment variables to authenticate your application, first set them to the +AWS IAM values needed for authentication. You can run the ``export`` command in your shell or +add the variables to a ``.env`` file, as shown in the following code example: + +.. tabs:: + + .. tab:: Shell Commands + :tabid: shell + + .. code-block:: sh + + export AWS_ACCESS_KEY_ID= + export AWS_SECRET_ACCESS_KEY= + export AWS_SESSION_TOKEN= + + .. tab:: .env File + :tabid: dotenv + + .. code-block:: php + + AWS_ACCESS_KEY_ID= + AWS_SECRET_ACCESS_KEY= + AWS_SESSION_TOKEN= + +.. important:: + + Don't percent-encode the values in these environment variables. + +After you set these environment variables, set the ``authMechanism`` +connection option to ``'MONGODB-AWS'``. + +.. _php-mongodb-aws-env-example: + +Example +``````` + +The following example sets the ``authMechanism`` connection option. +You can set this option in two ways: by passing an options array to the +``MongoDB\Client`` constructor or through a parameter in your connection URI. + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-aws-env-client + :end-before: end-mongodb-aws-env-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-aws-env-uri + :end-before: end-mongodb-aws-env-uri + +.. tip:: AWS Lambda + + AWS Lambda runtimes can automatically set these environment variables during + initialization. For more information about using environment variables in an AWS Lambda + environment, see `Using Lambda environment variables + `__ + in the AWS documentation. + +.. _php-mongodb-aws-oidc: + +AssumeRoleWithWebIdentity Request +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your application authenticates users for your EKS cluster from an OpenID Connect (OIDC) +identity provider, the driver can make an ``AssumeRoleWithWebIdentity`` request +to exchange the OIDC token for temporary AWS credentials for your application. + +To authenticate with temporary AWS IAM credentials returned by an +``AssumeRoleWithWebIdentity`` request, ensure that the AWS config file exists in your +environment and is configured correctly. To learn how to create and configure +an AWS config file, see `Configuration `__ +in the AWS documentation. + +After you configure your environment for an ``AssumeRoleWithWebIdentity`` request, +set the ``authMechanism`` connection option to ``'MONGODB-AWS'``. +To view an example that sets the ``authMechanism`` option, see the :ref:`authMechanism example +` on this page. + +.. tip:: + + For more information about using an ``AssumeRoleWithWebIdentity`` request to + authenticate your application, see the following AWS documentation: + + - `Authenticating users for your cluster from an OpenID Connect identity provider + `__ + - `AssumeRoleWithWebIdentity + `__ + +.. _php-mongodb-aws-ecs: + +ECS Metadata +~~~~~~~~~~~~ + +If your application runs in an Elastic Container Service (ECS) container, +the driver can automatically retrieve temporary AWS credentials from an +ECS endpoint. To do so, specify the URI of the ECS endpoint in an environment variable called +``AWS_CONTAINER_CREDENTIALS_RELATIVE_URI``. You can set this variable by running +the ``export`` shell command or adding it to your ``.env`` file, as shown in the following +example: + +.. tabs:: + + .. tab:: Shell Commands + :tabid: shell + + .. code-block:: sh + + export AWS_CONTAINER_CREDENTIALS_RELATIVE_URI= + + .. tab:: .env File + :tabid: dotenv + + .. code-block:: php + + AWS_CONTAINER_CREDENTIALS_RELATIVE_URI= + +After you set the environment variable, set the ``authMechanism`` +connection option to ``'MONGODB-AWS'``. To view an example that sets the +``authMechanism`` option, see the :ref:`authMechanism example +` on this page. + +.. _php-mongo-aws-ec2: + +EC2 Instance Metadata +~~~~~~~~~~~~~~~~~~~~~ + +The driver can automatically retrieve temporary AWS credentials from an +Amazon Elastic Cloud Compute (EC2) instance. To use temporary credentials from +within an EC2 instance, set the ``authMechanism`` connection option to ``'MONGODB-AWS'``. +To view an example that sets the ``authMechanism`` option, see the :ref:`authMechanism example +` on this page. + +.. note:: + + The {+php-library+} retrieves credentials from an EC2 instance only if the + environment variables described in the :ref:`php-mongodb-aws-env-vars` section + are not set. + +Additional Information +---------------------- + +To learn more about creating a ``MongoDB\Client`` object in the {+php-library+}, +see the :ref:`php-client` guide. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about the ``MongoDB\Client`` class, see :phpclass:`MongoDB\Client` +in the library API documentation. + +To view a full list of URI options that you can pass to a ``MongoDB\Client``, see +`MongoDB\\Driver\\Manager::__construct() Parameters +<{+php-manual+}/mongodb-driver-manager.construct.php#refsect1-mongodb-driver-manager.construct-parameters>`__ +in the extension API documentation. \ No newline at end of file From f0e562c79c535f1c198ddf57d5ef56a7c687bb80 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Wed, 25 Sep 2024 15:42:59 -0400 Subject: [PATCH 102/149] DOCSP-41989: Security landing page (#149) * DOCSP-41989: Security landing page * more info * edits * snooty.toml * edits * RR feedback * JM feedback --- snooty.toml | 1 + source/includes/authentication.php | 35 ++- .../usage-examples/connect-sample-app.php | 14 ++ source/security.txt | 208 ++++++++++++++++++ 4 files changed, 250 insertions(+), 8 deletions(-) create mode 100644 source/includes/usage-examples/connect-sample-app.php diff --git a/snooty.toml b/snooty.toml index efd33899..9cd0f222 100644 --- a/snooty.toml +++ b/snooty.toml @@ -25,6 +25,7 @@ toc_landing_pages = [ "/databases-collections", "/write", "/indexes", + "/security" "/data-formats" ] diff --git a/source/includes/authentication.php b/source/includes/authentication.php index 58557aca..7810406b 100644 --- a/source/includes/authentication.php +++ b/source/includes/authentication.php @@ -11,8 +11,8 @@ ]; $client = new MongoDB\Client( - 'mongodb://:', - $uriOptions, + 'mongodb://:', + $uriOptions, ); // end-scram-sha-256-client @@ -21,6 +21,25 @@ $client = new MongoDB\Client($uri); // end-scram-sha-256-uri +// start-scram-sha-1-client +$uriOptions = [ + 'username' => '', + 'password' => '', + 'authSource' => '', + 'authMechanism' => 'SCRAM-SHA-1', +]; + +$client = new MongoDB\Client( + 'mongodb://:', + $uriOptions, +); +// end-scram-sha-1-client + +// start-scram-sha-1-uri +$uri = 'mongodb://:@:/?authSource=admin&authMechanism=SCRAM-SHA-1'; +$client = new MongoDB\Client($uri); +// end-scram-sha-1-uri + // start-mongodb-X509-client $uriOptions = [ 'tls' => true, @@ -29,8 +48,8 @@ ]; $client = new MongoDB\Client( - 'mongodb://:', - $uriOptions, + 'mongodb://:', + $uriOptions, ); // end-mongodb-X509-client @@ -47,8 +66,8 @@ ]; $client = new MongoDB\Client( - 'mongodb://:', - $uriOptions, + 'mongodb://:', + $uriOptions, ); // end-mongodb-aws-client @@ -59,8 +78,8 @@ // start-mongodb-aws-env-client $client = new MongoDB\Client( - 'mongodb://:', - ['authMechanism' => 'MONGODB-AWS'] + 'mongodb://:', + ['authMechanism' => 'MONGODB-AWS'] ); // end-mongodb-aws-env-client diff --git a/source/includes/usage-examples/connect-sample-app.php b/source/includes/usage-examples/connect-sample-app.php new file mode 100644 index 00000000..d89319ff --- /dev/null +++ b/source/includes/usage-examples/connect-sample-app.php @@ -0,0 +1,14 @@ +test->command(['ping' => 1]); + echo 'Successfully pinged the MongoDB server.', PHP_EOL; +} catch (MongoDB\Driver\Exception\RuntimeException $e) { + printf("Failed to ping the MongoDB server: %s\n", $e->getMessage()); +} diff --git a/source/security.txt b/source/security.txt index b70e1a59..485595de 100644 --- a/source/security.txt +++ b/source/security.txt @@ -4,9 +4,217 @@ Secure Your Data ================ +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: ldap, authorize, ecs, aws, authenticate + :description: Learn how to use the PHP library to secure your data. + .. toctree:: :titlesonly: :maxdepth: 1 /security/authentication /security/in-use-encryption + +Overview +-------- + +MongoDB supports multiple mechanisms that you can use to authenticate your application. +This page contains code examples that demonstrate each of these mechanisms. + +.. tip:: + + To learn more about any of the mechanisms shown on this page, see the link + provided in each section. + +To use an authentication example from this page, copy the code example into the +:ref:`sample application ` or your own application. +Make sure to replace all placeholders in the code examples, such as ````, with +the relevant values for your MongoDB deployment. + +.. _php-auth-sample: + +.. include:: /includes/usage-examples/sample-app-intro.rst + +.. literalinclude:: /includes/usage-examples/connect-sample-app.php + :language: php + :copyable: true + :linenos: + :emphasize-lines: 5-7 + +SCRAM-SHA-256 +------------- + +The following code shows how to authenticate by using the ``SCRAM-SHA-256`` +authentication mechanism: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-scram-sha-256-client + :end-before: end-scram-sha-256-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-scram-sha-256-uri + :end-before: end-scram-sha-256-uri + +To learn more about SCRAM-SHA-256 authentication, see :ref:`php-scram-sha-256` in +the Authentication guide. + +SCRAM-SHA-1 +----------- + +The following code shows how to authenticate by using the ``SCRAM-SHA-1`` +authentication mechanism: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-scram-sha-1-client + :end-before: end-scram-sha-1-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-scram-sha-1-uri + :end-before: end-scram-sha-1-uri + +To learn more about SCRAM-SHA-1 authentication, see :ref:`php-scram-sha-1` in +the Authentication guide. + +MONGODB X.509 +------------- + +The following code shows how to create a connection URI to authenticate by using +the ``X.509`` authentication mechanism: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-X509-client + :end-before: end-mongodb-X509-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-X509-uri + :end-before: end-mongodb-X509-uri + +To learn more about X.509 authentication, see :ref:`php-x509` in +the Authentication guide. + +MONGODB-AWS +----------- + +The following sections show how to connect to MongoDB by using the ``MONGODB-AWS`` +authentication mechanism. When you use the ``MONGODB-AWS`` mechanism, the {+php-library+} +attempts to retrieve your AWS credentials from the following sources, in the order listed: + +1. Options passed to the ``MongoDB\Client`` constructor, either as part of the connection + string or the ``$uriOptions`` array parameter +#. Environment variables +#. AWS EKS ``AssumeRoleWithWebIdentity`` request +#. ECS container metadata +#. EC2 instance metadata + +Each section shows how to authenticate with ``MONGODB-AWS`` when retrieving your +AWS credentials from options passed to your client or the alternative external sources. + +To learn more about authenticating with AWS, see :ref:`php-mongo-aws` in the +Authentication guide. + +MongoDB\\Client Credentials +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code shows how to pass AWS credentials to the ``MongoDB\Client`` constructor +to authenticate with ``MONGODB-AWS``: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-aws-client + :end-before: end-mongodb-aws-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-aws-uri + :end-before: end-mongodb-aws-uri + +External Credentials +~~~~~~~~~~~~~~~~~~~~ + +The following code shows how to authenticate with ``MONGODB-AWS`` when +obtaining credentials from environment variables, an ``AssumeRoleWithWebIdentity`` +request, ECS metadata, or EC2 instance metadata: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-aws-env-client + :end-before: end-mongodb-aws-env-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/authentication.php + :language: php + :dedent: + :start-after: start-mongodb-aws-env-uri + :end-before: end-mongodb-aws-env-uri + +To learn more about authenticating with AWS by obtaining external +credentials, see the following sections in the Authentication guide: + +- :ref:`php-mongo-aws-environment` +- :ref:`php-mongo-aws-assume-role` +- :ref:`php-mongo-aws-ecs` +- :ref:`php-mongo-aws-ec2` From f31eb3e66b5e4fac73541382ebc8c084a1533285 Mon Sep 17 00:00:00 2001 From: Mike Woofter <108414937+mongoKart@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:51:51 -0500 Subject: [PATCH 103/149] DOCSP-41962 - Stable API (#117) Co-authored-by: Jeremy Mikola --- snooty.toml | 6 +- source/connect/stable-api.txt | 119 +++++++++++++++++++++++++ source/includes/connect/stable-api.php | 18 ++++ 3 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 source/connect/stable-api.txt create mode 100644 source/includes/connect/stable-api.php diff --git a/snooty.toml b/snooty.toml index 9cd0f222..051763b9 100644 --- a/snooty.toml +++ b/snooty.toml @@ -36,8 +36,10 @@ php-library = "MongoDB PHP Library" [constants] php-library = "MongoDB PHP Library" -library-short = "PHP library" -stable-api = "Stable API" +driver-short = "PHP library" +extension-short = "PHP extension" mdb-server = "MongoDB Server" +stable-api = "Stable API" +library-short = "PHP library" api = "https://www.mongodb.com/docs/php-library/current/reference" php-manual = "https://www.php.net/manual/en" diff --git a/source/connect/stable-api.txt b/source/connect/stable-api.txt new file mode 100644 index 00000000..d65bae63 --- /dev/null +++ b/source/connect/stable-api.txt @@ -0,0 +1,119 @@ +.. _php-stable-api: + +============== +{+stable-api+} +============== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: compatible, backwards, upgrade + +.. note:: + + The {+stable-api+} feature requires {+mdb-server+} 5.0 or later. + +Overview +-------- + +In this guide, you can learn how to specify **{+stable-api+}** compatibility when +connecting to a MongoDB deployment. + +The {+stable-api+} feature forces the server to run operations with behaviors compatible +with the API version you specify. When you update either your library or server version, +the API version changes, which can change the way these operations behave. +Using the {+stable-api+} ensures consistent responses from the server and +provides long-term API stability for your application. + +The following sections describe how you can enable and customize {+stable-api+} for +your MongoDB client. For more information about the {+stable-api+}, including a list of +the commands it supports, see :manual:`Stable API ` in the +{+mdb-server+} manual. + +Enable the {+stable-api+} +------------------------- + +To enable the {+stable-api+}, perform the following steps: + +1. Construct a ``MongoDB\Driver\ServerApi`` object and pass the {+stable-api+} + version you want to use. Currently, the library supports only version 1. +#. Construct a ``MongoDB\Client`` object. For the ``driverOptions`` parameter, pass an + array that contains the ``serverApi`` option. Set this option to the + ``MongoDB\Driver\ServerApi`` object you created in the previous step. + +The following code example shows how to specify {+stable-api+} version 1: + +.. literalinclude:: /includes/connect/stable-api.php + :language: php + :copyable: true + :start-after: // start-specify-v1 + :end-before: // end-specify-v1 + :emphasize-lines: 3-4 + +.. note:: + + After you create a ``MongoDB\Client`` instance with + a specified API version, all commands you run with the client use the specified + version. If you need to run commands using more than one version of the + {+stable-api+}, create a new ``MongoDB\Client`` instance. + +.. _stable-api-options: + +Configure the {+stable-api+} +------------------------ + +The ``MongoDB\Driver\ServerApi`` constructor also accepts the following optional parameters. +You can use these parameters to customize the behavior of the {+stable-api+}. + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + :widths: 25,75 + + * - Parameter + - Description + + * - strict + - | **Optional**. When ``true``, if you call a command that isn't part of + the declared API version, the server raises an exception. + | + | Default: ``null``. If this parameter is null, the server applies its default + value of ``false``. + + * - deprecationErrors + - | **Optional**. When ``true``, if you call a command that is deprecated in the + declared API version, the server raises an exception. + | + | Default: ``null``. If this parameter is null, the server applies its default + value of ``false``. + +The following code example shows how you can use these parameters when constructing a +``MongoDB\Driver\ServerApi`` object: + +.. literalinclude:: /includes/connect/stable-api.php + :language: php + :copyable: true + :start-after: // start-stable-api-options + :end-before: // end-stable-api-options + :emphasize-lines: 3-4 + +API Documentation +----------------- + +For more information about the ``MongoDB\Client`` class, see the following {+driver-short+} +API documentation: + +- :phpclass:`MongoDB\Client` + +For more information about the ``MongoDB\Driver\ServerApi`` class, see the following +{+extension-short+} API documentation: + +- `MongoDB\\Driver\\ServerApi `__ \ No newline at end of file diff --git a/source/includes/connect/stable-api.php b/source/includes/connect/stable-api.php new file mode 100644 index 00000000..f84470c4 --- /dev/null +++ b/source/includes/connect/stable-api.php @@ -0,0 +1,18 @@ +:"; + +$driverOptions = ['serverApi' => new MongoDB\Driver\ServerApi('1')]; + +$client = new MongoDB\Client($uri, [], $driverOptions); +// end-specify-v1 + +// start-stable-api-options +$uri = "mongodb://:"; + +$serverApi = new MongoDB\Driver\ServerApi('1', strict: true, deprecationErrors: true); +$driverOptions = ['serverApi' => $serverApi]; + +$client = new MongoDB\Client($uri, [], $driverOptions); +// end-stable-api-options From 585da96f2b6d54316b029f746cba71b37e7bb2d6 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 17:44:41 -0400 Subject: [PATCH 104/149] DOCSP-41992 Upgrade versions --- snooty.toml | 5 ++- source/upgrade.txt | 109 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 source/upgrade.txt diff --git a/snooty.toml b/snooty.toml index 051763b9..940aaa67 100644 --- a/snooty.toml +++ b/snooty.toml @@ -25,8 +25,9 @@ toc_landing_pages = [ "/databases-collections", "/write", "/indexes", - "/security" - "/data-formats" + "/security", + "/data-formats", + "/upgrade" ] sharedinclude_root = "https://raw.githubusercontent.com/10gen/docs-shared/main/" diff --git a/source/upgrade.txt b/source/upgrade.txt new file mode 100644 index 00000000..11628e3c --- /dev/null +++ b/source/upgrade.txt @@ -0,0 +1,109 @@ +.. php-upgrade: + +======================= +Upgrade Driver Versions +======================= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: compatibility, backwards compatibility + +Overview +-------- + +This page describes the changes you must make to your application +when you upgrade to a new version of the {+driver-short+}. + +This page describes the changes you must make to your application +when you upgrade to a new version of the {+driver-short+}. + +Before you upgrade, perform the following actions: + +- Ensure the new {+driver-short+} version is compatible with the {+mdb-server+} versions + your application connects to and the PHP version your + application compiles with. For version compatibility information, see the + :ref:`{+driver-short+} Compatibility ` + page. +- Address any breaking changes between the driver version + your application is using and your planned upgrade version in the + :ref:`Breaking Changes ` section. + +.. tip:: + + To ensure compatibility across {+mdb-server+} versions when + upgrading driver versions, use the :ref:`{+stable-api+} `. + +.. _php-breaking-changes: + +Breaking Changes +---------------- + +A breaking change is a change of a convention or a behavior starting in a specific +version of the driver. This type of change may prevent your application from working +properly if not addressed before upgrading the driver. + +The breaking changes in this section are categorized by the driver version that introduced +them. When upgrading driver versions, address all the breaking changes between the current +and upgrade versions. + +For more information on release changes, see the release notes and associated +JIRA tickets for each release on `GitHub `__. + +Version 1.20 Breaking Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This driver version introduces the following breaking changes: + +- Drops support for {+mdb-server+} 3.6. + +- Deprecate iterators for database, collection, and index enumeration. + +Version 1.18 Breaking Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This driver version introduces the following breaking changes: + +- Deprecate setting ``disableMD5`` to ``false`` when instantiating a Bucket due to + deprecated MD5 encoding. The default value for the setting is now ``true``. + +Version 1.17 Breaking Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This driver version introduces the following breaking changes: + +- Upgrades the ``mongodb`` extension requirement to 1.17.0. + +- Requires PHP 7.4 or newer. + +- Removes support for PHP 7.2 and 7.3. + +- Remove aggregate compatibility logic for {+mdb-server+} versions less than + 3.6, including removing the ``useCursor`` option. + +Version 1.16 Breaking Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Upgrades the ``mongodb`` extension requirement to 1.16.0. + +- Deprecate ``IndexInfo::isGeoHaystack()``. ``geoHaystack`` was removed in + {+mdb-server+} 5.0 and later. + +- Drop support for Composer 1.x. + +- Remove ``$server`` argument in ``Explainable::getCommandDocument``. + +- Remove ``getNonce`` command usage for {+mdb-server+} 6.2 and later. + +Version 1.15 Breaking Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Upgrades the ``mongodb`` extension requirement to 1.15.0. From 15e475f0da0d0fea1e72a68b551b833cc81ae654 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 17:52:14 -0400 Subject: [PATCH 105/149] toc --- source/index.txt | 1 + source/upgrade.txt | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/source/index.txt b/source/index.txt index 7ffdd83a..0d1e9441 100644 --- a/source/index.txt +++ b/source/index.txt @@ -22,6 +22,7 @@ MongoDB PHP Library /data-formats /compatibility /whats-new + /upgrade FAQ /reference diff --git a/source/upgrade.txt b/source/upgrade.txt index 11628e3c..231e3cd0 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -92,6 +92,8 @@ This driver version introduces the following breaking changes: Version 1.16 Breaking Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This driver version introduces the following breaking changes: + - Upgrades the ``mongodb`` extension requirement to 1.16.0. - Deprecate ``IndexInfo::isGeoHaystack()``. ``geoHaystack`` was removed in @@ -106,4 +108,6 @@ Version 1.16 Breaking Changes Version 1.15 Breaking Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This driver version introduces the following breaking changes: + - Upgrades the ``mongodb`` extension requirement to 1.15.0. From 9670327ee8ad148ab7258134d2500dab13192fa8 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 18:03:53 -0400 Subject: [PATCH 106/149] edits --- source/upgrade.txt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index 231e3cd0..7e7d8df2 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -23,15 +23,12 @@ Overview This page describes the changes you must make to your application when you upgrade to a new version of the {+driver-short+}. -This page describes the changes you must make to your application -when you upgrade to a new version of the {+driver-short+}. - Before you upgrade, perform the following actions: - Ensure the new {+driver-short+} version is compatible with the {+mdb-server+} versions your application connects to and the PHP version your application compiles with. For version compatibility information, see the - :ref:`{+driver-short+} Compatibility ` + :ref:`{+php-library+} Compatibility ` page. - Address any breaking changes between the driver version your application is using and your planned upgrade version in the @@ -84,10 +81,8 @@ This driver version introduces the following breaking changes: - Requires PHP 7.4 or newer. -- Removes support for PHP 7.2 and 7.3. - -- Remove aggregate compatibility logic for {+mdb-server+} versions less than - 3.6, including removing the ``useCursor`` option. +- Remove aggregate compatibility logic, like the ``useCursor`` option, for + {+mdb-server+} versions less than 3.6. Version 1.16 Breaking Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 84825148b60c6b1cb6a5258cbbd369d3c8ea7fa8 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 18:15:00 -0400 Subject: [PATCH 107/149] how to upgrade sections --- source/upgrade.txt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index 7e7d8df2..a1e9945f 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -20,8 +20,12 @@ Upgrade Driver Versions Overview -------- -This page describes the changes you must make to your application -when you upgrade to a new version of the {+driver-short+}. +This page describes how to upgrade your driver to a new version and the changes +you must make to your application when you upgrade to a new version of the +{+driver-short+}. + +How to Upgrade +-------------- Before you upgrade, perform the following actions: @@ -39,6 +43,17 @@ Before you upgrade, perform the following actions: To ensure compatibility across {+mdb-server+} versions when upgrading driver versions, use the :ref:`{+stable-api+} `. +To upgrade your driver version, replace "version number" with the version number +you would like to upgrade to and run the following command in your application's +directory: + +.. code-block:: bash + + composer require mongodb/mongodb: + +Installation instructions for the ``mongodb`` extension may be found in the +`PHP.net documentation `__. + .. _php-breaking-changes: Breaking Changes From dfe83b7b060915bf3ce6d63ad74a2c6f58888706 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 18:19:04 -0400 Subject: [PATCH 108/149] style --- source/upgrade.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index a1e9945f..a36e4003 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -44,7 +44,7 @@ Before you upgrade, perform the following actions: upgrading driver versions, use the :ref:`{+stable-api+} `. To upgrade your driver version, replace "version number" with the version number -you would like to upgrade to and run the following command in your application's +you want to upgrade to and run the following command in your application's directory: .. code-block:: bash From 6e3538dadb11b4d16a304192a59e67348443f62d Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 18:21:21 -0400 Subject: [PATCH 109/149] edit --- source/upgrade.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index a36e4003..7bec815c 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -20,9 +20,9 @@ Upgrade Driver Versions Overview -------- -This page describes how to upgrade your driver to a new version and the changes -you must make to your application when you upgrade to a new version of the -{+driver-short+}. +On this page, you can learn how to upgrade your driver to a new version. This +page also includes the changes you must make to your application when you +upgrade to a new version of the {+driver-short+}. How to Upgrade -------------- From 6610b561f2f13ca6ea06f044be9ee542bb07e779 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Wed, 25 Sep 2024 18:24:27 -0400 Subject: [PATCH 110/149] edit --- source/upgrade.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index 7bec815c..068841f4 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -22,7 +22,7 @@ Overview On this page, you can learn how to upgrade your driver to a new version. This page also includes the changes you must make to your application when you -upgrade to a new version of the {+driver-short+}. +upgrade to a new version of the {+php-library+}. How to Upgrade -------------- From 89883229617e2d6b15672e3bda3cba34b22c2817 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 26 Sep 2024 10:15:59 -0400 Subject: [PATCH 111/149] review comments --- source/upgrade.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index 068841f4..c76df8fd 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -43,16 +43,16 @@ Before you upgrade, perform the following actions: To ensure compatibility across {+mdb-server+} versions when upgrading driver versions, use the :ref:`{+stable-api+} `. -To upgrade your driver version, replace "version number" with the version number +To upgrade your driver version, replace ```` with the version number you want to upgrade to and run the following command in your application's directory: .. code-block:: bash - composer require mongodb/mongodb: + composer require mongodb/mongodb: Installation instructions for the ``mongodb`` extension may be found in the -`PHP.net documentation `__. +:php:`PHP.net documentation `. .. _php-breaking-changes: @@ -77,14 +77,14 @@ This driver version introduces the following breaking changes: - Drops support for {+mdb-server+} 3.6. -- Deprecate iterators for database, collection, and index enumeration. +- Deprecates iterators for database, collection, and index enumeration. Version 1.18 Breaking Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This driver version introduces the following breaking changes: -- Deprecate setting ``disableMD5`` to ``false`` when instantiating a Bucket due to +- Deprecates setting ``disableMD5`` to ``false`` when instantiating a Bucket due to deprecated MD5 encoding. The default value for the setting is now ``true``. Version 1.17 Breaking Changes @@ -96,7 +96,7 @@ This driver version introduces the following breaking changes: - Requires PHP 7.4 or newer. -- Remove aggregate compatibility logic, like the ``useCursor`` option, for +- Removes aggregate compatibility logic, like the ``useCursor`` option, for {+mdb-server+} versions less than 3.6. Version 1.16 Breaking Changes @@ -106,14 +106,14 @@ This driver version introduces the following breaking changes: - Upgrades the ``mongodb`` extension requirement to 1.16.0. -- Deprecate ``IndexInfo::isGeoHaystack()``. ``geoHaystack`` was removed in +- Deprecates ``IndexInfo::isGeoHaystack()``. ``geoHaystack`` was removed in {+mdb-server+} 5.0 and later. -- Drop support for Composer 1.x. +- Drops support for Composer 1.x. -- Remove ``$server`` argument in ``Explainable::getCommandDocument``. +- Removes ``$server`` argument in ``Explainable::getCommandDocument``. -- Remove ``getNonce`` command usage for {+mdb-server+} 6.2 and later. +- Removes ``getNonce`` command usage for {+mdb-server+} 6.2 and later. Version 1.15 Breaking Changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From ce8408f78a4b4cb23dfcd99693973aaef8872f59 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 26 Sep 2024 10:16:22 -0400 Subject: [PATCH 112/149] ref --- source/upgrade.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index c76df8fd..dbd3a41b 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -1,4 +1,4 @@ -.. php-upgrade: +.. _php-upgrade: ======================= Upgrade Driver Versions From 13de83c4877c2bc850b2311548c09f0d7b49c110 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 26 Sep 2024 11:14:08 -0400 Subject: [PATCH 113/149] Revise descriptions for server opening/closed events --- source/monitoring/cluster-monitoring.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/monitoring/cluster-monitoring.txt b/source/monitoring/cluster-monitoring.txt index d9d9901e..0093aa47 100644 --- a/source/monitoring/cluster-monitoring.txt +++ b/source/monitoring/cluster-monitoring.txt @@ -100,10 +100,10 @@ documentation, and a description of when the event is published: type changing from secondary to primary. * - :php:`ServerOpeningEvent ` - - Created when a server connection is established. + - Created when a new server is added to the topology. * - :php:`ServerClosedEvent ` - - Created when a server connection is closed. + - Created when an existing server is removed from the topology. * - :php:`TopologyChangedEvent ` - Created when the topology description changes, such as when there From 993076b2f94999e6d28b80700acde22f016fb681 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Thu, 26 Sep 2024 13:07:51 -0400 Subject: [PATCH 114/149] DOCSP-43204: Connection landing page (#147) * DOCSP-43204: Connection landing page * toc edit * edits * remove compression * fix * sample app * snooty * JM feedback * replica set * JM feedback 2 * JM last feedback --- snooty.toml | 1 + source/connect.txt | 418 ++++++++++++++++++ .../usage-examples/connect-code-examples.php | 177 ++++++++ source/index.txt | 1 + 4 files changed, 597 insertions(+) create mode 100644 source/connect.txt create mode 100644 source/includes/usage-examples/connect-code-examples.php diff --git a/snooty.toml b/snooty.toml index 051763b9..76e5f009 100644 --- a/snooty.toml +++ b/snooty.toml @@ -22,6 +22,7 @@ toc_landing_pages = [ "/reference/class/MongoDBModelDatabaseInfo", "/reference/class/MongoDBModelIndexInfo", "/get-started", + "/connect", "/databases-collections", "/write", "/indexes", diff --git a/source/connect.txt b/source/connect.txt new file mode 100644 index 00000000..cc4ff021 --- /dev/null +++ b/source/connect.txt @@ -0,0 +1,418 @@ +.. _php-connect: + +================== +Connect to MongoDB +================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :description: Learn how to use the PHP library to connect to MongoDB. + :keywords: client, ssl + +.. toctree:: + :titlesonly: + :maxdepth: 1 + + /connect/client + /connect/connection-targets + /connect/tls + +.. TODO: + /connect/connection-options + /connect/stable-api + +Overview +-------- + +This page contains code examples that show how to connect your PHP application +to MongoDB with various settings. + +.. tip:: + + To learn more about the connection options on this page, see the link + provided in each section. + +To use a connection example from this page, copy the code example into the +:ref:`sample application ` or your own application. +Make sure to replace all placeholders in the code examples, such as +````, with the relevant values for your MongoDB deployment. + +.. _php-connect-sample: + +.. include:: /includes/usage-examples/sample-app-intro.rst + +.. literalinclude:: /includes/usage-examples/connect-sample-app.php + :language: php + :copyable: true + :linenos: + :emphasize-lines: 5-7 + +.. important:: Percent-Encoding + + You must :wikipedia:`percent-encode ` a username and password before + you include them in a MongoDB URI. You can use the ``rawurlencode()`` method to encode + these values according to the URI syntax specified in `RFC 3986 `__. + Don't percent-encode the username or password when passing them in an options array + parameter to the ``MongoDB\Client`` constructor. + +Connection +---------- + +Atlas +~~~~~ + +The following code shows how to connect to a MongoDB Atlas deployment: + +.. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-atlas + :end-before: end-atlas + +To learn more about connecting to an Atlas deployment, see :ref:`php-connection-atlas` +in the Connection Targets guide. + +Local Deployment +~~~~~~~~~~~~~~~~ + +The following code shows how to connect to a local MongoDB deployment: + +.. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-local + :end-before: end-local + +.. note:: + + If you don't specify the ``$uri`` parameter, the connection URI defaults to + ``'mongodb://127.0.0.1:27017'``. + +To learn more about connecting to a local deployment, see :ref:`php-connection-local` +in the Connection Targets guide. + +Replica Set +~~~~~~~~~~~ + +The following code shows how to connect to a replica set deployment: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-replica-set-client + :end-before: end-replica-set-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-replica-set-uri + :end-before: end-replica-set-uri + +.. tip:: + + To maintain your connection to a replica set deployment when one + host is down, you can provide multiple replica set members in the + connection URI. + +To learn more about connecting to a replica set, see :ref:`php-connection-replica-set` +in the Connection Targets guide. + +Transport Layer Security (TLS) +------------------------------ + +Enable TLS +~~~~~~~~~~ + +The following code shows how to enable TLS for the connection to your +MongoDB instance: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-enable-tls-client + :end-before: end-enable-tls-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-enable-tls-uri + :end-before: end-enable-tls-uri + +To learn more about enabling TLS, see :ref:`php-enable-tls` in +the TLS Configuration guide. + +Specify a Certificate Authority (CA) File +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code shows how to specify the path to your CA file +for the connection to your MongoDB instance: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-ca-file-client + :end-before: end-ca-file-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-ca-file-uri + :end-before: end-ca-file-uri + +To learn more about specifying a CA file, see :ref:`php-specify-ca-file` in +the TLS Configuration guide. + +Disable OCSP Checks +~~~~~~~~~~~~~~~~~~~ + +The following code shows how to prevent the driver from contacting +the OCSP endpoint: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-disable-ocsp-client + :end-before: end-disable-ocsp-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-disable-ocsp-uri + :end-before: end-disable-ocsp-uri + +To learn more about disabling OCSP checks, see :ref:`php-disable-ocsp` in +the TLS Configuration guide. + +Specify a Certificate Revocation List (CRL) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code shows how to instruct the driver to verify the server's +certificate against a CRL: + +.. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-crl + :end-before: end-crl + +To learn more about specifying a CRL, see :ref:`php-crl` in the TLS +configuration guide. + +Present a Client Certificate +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code shows how to specify the client certificate that +the driver presents to your MongoDB deployment: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-client-cert-client + :end-before: end-client-cert-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-client-cert-uri + :end-before: end-client-cert-uri + +To learn more about specifying a client certificate, see :ref:`php-client-cert` in +the TLS Configuration guide. + +Provide a Certificate Key File Password +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code shows how to specify the password for your +client certificate: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-key-file-client + :end-before: end-key-file-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-key-file-uri + :end-before: end-key-file-uri + +.. important:: + + When replacing the ```` placeholder in the connection URI, ensure + that you :wikipedia:`percent-encode ` the value. + +To learn more about providing a key file password, see :ref:`php-key-file-password` in +the TLS Configuration guide. + +Allow Insecure TLS +~~~~~~~~~~~~~~~~~~ + +The following code shows how to relax TLS constraints, which has the same +effect as disabling both :ref:`certificate validation ` +and :ref:`hostname verification `: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-insecure-tls-client + :end-before: end-insecure-tls-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-insecure-tls-uri + :end-before: end-insecure-tls-uri + +To learn more about allowing insecure TLS, see :ref:`php-insecure-tls` in +the TLS Configuration guide. + +.. warning:: + + Setting the ``tlsInsecure`` option to ``true`` might expose your application + to security risks. Enabling this option makes your application insecure and + potentially vulnerable to expired certificates and to foreign processes posing + as valid client instances. + +.. _php-connect-disable-cert: + +Disable Certificate Validation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code shows how to disable certificate validation: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-disable-cert-client + :end-before: end-disable-cert-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-disable-cert-uri + :end-before: end-disable-cert-uri + +To learn more about disabling certificate validation, see :ref:`php-insecure-tls` in +the TLS Configuration guide. + +.. _php-connect-disable-hostname: + +Disable Hostname Verification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following code shows how to disable hostname verification: + +.. tabs:: + + .. tab:: MongoDB\\Client + :tabid: Client + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-disable-hostname-client + :end-before: end-disable-hostname-client + + .. tab:: Connection URI + :tabid: connectionstring + + .. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-disable-hostname-uri + :end-before: end-disable-hostname-uri + +To learn more about disabling hostname verification, see :ref:`php-insecure-tls` in +the TLS Configuration guide. + +{+stable-api+} +-------------- + +The following code shows how to enable the {+stable-api+} for the +connection to your MongoDB instance: + +.. literalinclude:: /includes/usage-examples/connect-code-examples.php + :language: php + :dedent: + :start-after: start-stable-api + :end-before: end-stable-api + +To learn more about the {+stable-api+}, see the :ref:`php-stable-api` guide. + +.. TODO: + Network Compression + ------------------- \ No newline at end of file diff --git a/source/includes/usage-examples/connect-code-examples.php b/source/includes/usage-examples/connect-code-examples.php new file mode 100644 index 00000000..cc994df0 --- /dev/null +++ b/source/includes/usage-examples/connect-code-examples.php @@ -0,0 +1,177 @@ +'; +$client = new MongoDB\Client($uri); +// end-atlas + +// Connects to a replica set using client options +// start-replica-set-client +$client = new MongoDB\Client( + 'mongodb://:/', + ['replicaSet' => ''], +); +// end-replica-set-client + +// Connects to a replica set using a connection URI parameter +// start-replica-set-uri +$uri = 'mongodb://:/?replicaSet='; +$client = new MongoDB\Client($uri); +// end-replica-set-uri + +// Connects to a MongoDB deployment and enables TLS using client +// options +// start-enable-tls-client +$client = new MongoDB\Client( + 'mongodb://:/', + ['tls' => true], +); +// end-enable-tls-client + +// Connects to a MongoDB deployment and enables TLS using connection URI +// parameters +// start-enable-tls-uri +$uri = 'mongodb://:/?tls=true'; +$client = new MongoDB\Client($uri); +// end-enable-tls-uri + +// Connects to a MongoDB deployment, enables TLS, and specifies the path to +// a CA file using client options +// start-ca-file-client +$client = new MongoDB\Client( + 'mongodb://:/', + ['tls' => true, 'tlsCAFile' => '/path/to/ca.pem'], +); +// end-ca-file-client + +// Connects to a MongoDB deployment, enables TLS, and specifies the path to +// a CA file using connection URI parameters +// start-ca-file-uri +$uri = 'mongodb://:/?tls=true&tlsCAFile=/path/to/ca.pem'; +$client = new MongoDB\Client($uri); +// end-ca-file-uri + +// Connects to a MongoDB deployment, enables TLS, and prevents OCSP endpoint checks +// using client options +// start-disable-ocsp-client +$client = new MongoDB\Client( + 'mongodb://:/', + ['tls' => true, 'tlsDisableOCSPEndpointCheck' => true], +); +// end-disable-ocsp-client + +// Connects to a MongoDB deployment, enables TLS, and prevents OCSP endpoint checks +// using connection URI parameters +// start-disable-ocsp-uri +$uri = 'mongodb://:/?tls=true&tlsDisableOCSPEndpointCheck=true'; +$client = new MongoDB\Client($uri); +// end-disable-ocsp-uri + +// Connects to a TLS-enabled deployment and instructs the driver to check the +// server certificate against a CRL +// start-crl +$client = new MongoDB\Client( + 'mongodb://:/', + ['tls' => true], + ['crl_file' => '/path/to/file.pem'], +); +// end-crl + +// Presents a client certificate to prove identity +// using client options +// start-client-cert-client +$client = new MongoDB\Client( + 'mongodb://:/', + ['tls' => true, 'tlsCertificateKeyFile' => '/path/to/client.pem'], +); +// end-client-cert-client + +// Presents a client certificate to prove identity +// using connection URI parameters +// start-client-cert-uri +$uri = 'mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/client.pem'; +$client = new MongoDB\Client($uri); +// end-client-cert-uri + +// Specifies the password for a client certificate using client options +// start-key-file-client +$client = new MongoDB\Client( + 'mongodb://:/', + [ + 'tls' => true, + 'tlsCertificateKeyFile' => '/path/to/client.pem', + 'tlsCertificateKeyFilePassword' => '' + ], +); +// end-key-file-client + +// Specifies the password for a client certificate using connection URI parameters +// start-key-file-uri +$uri = 'mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/client.pem&tlsCertificateKeyFilePassword='; +$client = new MongoDB\Client($uri); +// end-key-file-uri + +// Connects to a TLS-enabled deployment and disables server certificate verification +// using client options +// start-insecure-tls-client +$client = new MongoDB\Client( + 'mongodb://:/', + ['tls' => true, 'tlsInsecure' => true], +); +// end-insecure-tls-client + +// Connects to a TLS-enabled deployment and disables server certificate verification +// using connection URI parameters +// start-insecure-tls-uri +$uri = 'mongodb://:/?tls=true&tlsInsecure=true'; +$client = new MongoDB\Client($uri); +// end-insecure-tls-uri + +// Disables certificate validation using client options +// start-disable-cert-client +$client = new MongoDB\Client( + 'mongodb://:/', + ['tls' => true, 'tlsAllowInvalidCertificates' => true], +); +// end-disable-cert-client + +// Disables certificate validation using connection URI parameters +// start-disable-cert-uri +$uri = 'mongodb://:/?tls=true&tlsAllowInvalidCertificates=true'; +$client = new MongoDB\Client($uri); +// end-disable-cert-uri + +// Connects to a TLS-enabled deployment and disables hostname verification +// using client options +// start-disable-hostname-client +$client = new MongoDB\Client( + 'mongodb://:/', + ['tls' => true, 'tlsAllowInvalidHostnames' => true], +); +// end-disable-hostname-client + +// Connects to a TLS-enabled deployment and disables hostname verification +// using connection URI parameters +// start-disable-hostname-uri +$uri = 'mongodb://:/?tls=true&tlsAllowInvalidHostnames=true'; +$client = new MongoDB\Client($uri); +// end-disable-hostname-uri + +// Connects to a MongoDB deployment and enables the stable API +// start-stable-api +$driverOptions = ['serverApi' => new MongoDB\Driver\ServerApi('1')]; +$client = new MongoDB\Client( + 'mongodb://:/', + [], + $driverOptions, +); +// end-stable-api diff --git a/source/index.txt b/source/index.txt index 7ffdd83a..f8d9c36f 100644 --- a/source/index.txt +++ b/source/index.txt @@ -11,6 +11,7 @@ MongoDB PHP Library :titlesonly: Get Started + /connect /databases-collections /read /write From 61dc28d6c244957098f753a94484f746dc0d97f9 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 26 Sep 2024 13:30:39 -0400 Subject: [PATCH 115/149] DOCSP-43819: php 1.20 release --- config/redirects | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/redirects b/config/redirects index bf1988da..151fef50 100644 --- a/config/redirects +++ b/config/redirects @@ -1,9 +1,9 @@ define: base https://www.mongodb.com/docs/php-library define: prefix docs/php-library raw: ${prefix}/ -> ${base}/current -define: versions v1.1 v1.2 v1.3 v1.4 v1.5 v1.6 v1.7 v1.8 v1.9 v1.10 v1.11 v1.12 v1.13 v1.15 v1.16 v1.17 v1.18 v1.19 master +define: versions v1.1 v1.2 v1.3 v1.4 v1.5 v1.6 v1.7 v1.8 v1.9 v1.10 v1.11 v1.12 v1.13 v1.15 v1.16 v1.17 v1.18 v1.19 v1.20 master symlink: upcoming -> master -symlink: current -> v1.19 +symlink: current -> v1.20 (v1.16-*]: ${prefix}/${version}/tutorial/client-side-encryption/ -> ${base}/${version}/tutorial/encryption/ [v1.16]: ${prefix}/${version}/tutorial/encryption/ -> ${base}/${version}/ From 014899b507ead1cdead3e54b791e9064a400be40 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 26 Sep 2024 13:34:11 -0400 Subject: [PATCH 116/149] fix --- snooty.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snooty.toml b/snooty.toml index 76e5f009..d2d18efa 100644 --- a/snooty.toml +++ b/snooty.toml @@ -26,7 +26,7 @@ toc_landing_pages = [ "/databases-collections", "/write", "/indexes", - "/security" + "/security", "/data-formats" ] From 992b952d0fe6be4c167598a99d989d94e36aadd9 Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 6 Sep 2024 11:56:06 -0400 Subject: [PATCH 117/149] DOCSP-41956: run a command --- source/includes/write/run-command.php | 19 +++ source/write/run-command.txt | 179 ++++++++++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 source/includes/write/run-command.php create mode 100644 source/write/run-command.txt diff --git a/source/includes/write/run-command.php b/source/includes/write/run-command.php new file mode 100644 index 00000000..eeff43cd --- /dev/null +++ b/source/includes/write/run-command.php @@ -0,0 +1,19 @@ +'); + +// start-runcommand +$database = $client->plants; + +$countCommand = ['count' => 'flowers']; +$explainCommand = ['explain' => $countCommand, 'verbosity' => 'queryPlanner']; + +$result = $database->command($explainCommand); +// end-runcommand + +var_dump($result->toArray()); + diff --git a/source/write/run-command.txt b/source/write/run-command.txt new file mode 100644 index 00000000..e7b8a4b9 --- /dev/null +++ b/source/write/run-command.txt @@ -0,0 +1,179 @@ +.. _php-run-command: + +====================== +Run a Database Command +====================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: administration, code example + +Overview +-------- + +In this guide, you can learn how to use the {+php-library+} +to run a database command. You can use database commands to perform a +variety of administrative and diagnostic tasks, such as fetching server +statistics, initializing a replica set, or running an aggregation pipeline. + +.. important:: Prefer Library Methods to Database Commands + + The library provides wrapper methods for many database commands. + We recommend using these methods instead of executing database + commands when possible. + + To perform administrative tasks, use the :mongosh:`MongoDB Shell ` + instead of the {+php-library+}. Calling the ``db.runCommand()`` + method inside the shell is the preferred way to issue database + commands, as it provides a consistent interface between the shell and + drivers or libraries. + +.. _php-execute-command: + +Execute a Command +----------------- + +To run a database command, you must specify the command and any relevant +parameters in a command document, then pass the command document to the +``command()`` method. This method returns a ``Cursor`` object. + +The following code shows how you can use the ``command()`` +method to run the ``hello`` command, which returns information about +the current member's role in the replica set, on a database: + +.. code-block:: php + + $result = $database->command(['ping' => 1]); + +To find a link to a full list of database commands and corresponding +parameters, see the :ref:`Additional Information section +`. + +.. note:: Read Preference + + The ``command()`` method does not + obey the read preference you might have set on your ``Database`` + instance elsewhere in your code. By default, ``command()`` uses the ``primary`` + read preference. + + You can set a read preference for command execution by setting one + in the options parameter, as shown in the following code: + + .. code-block:: php + + $readPref = new MongoDB\Driver\ReadPreference('primaryPreferred'); + $result = $database->command(['ping' => 1], ['readPreference' => $readPref]); + + For more information on read preference options, see :manual:`Read + Preference ` in the Server manual. + +.. _php-command-response: + +Response +-------- + +The ``command()`` method returns a ``Cursor`` object that contains +the response from the database after the command has been executed. + +Each database command performs a different function, so the response +content can vary depending on the command executed. However, every +response contains a document with the following fields: + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Field + - Description + + * - + - Fields specific to the database command. For example, + ``count`` returns the ``n`` field and ``explain`` returns the + ``queryPlanner`` field. + + * - ``ok`` + - Whether the command has succeeded (``1``) + or failed (``0``). + + * - ``operationTime`` + - The logical time of the operation. MongoDB uses the + logical time to order operations. + + .. seealso:: + + To learn more about logical time, see our blog post about the + :website:`Global Logical Clock `. + + * - ``$clusterTime`` + - A document that contains the signed cluster time. Cluster time is a + logical time used for the ordering of operations. + + This document contains the following fields: + + - ``clusterTime``, the timestamp of the highest known cluster time for the member + - ``signature``, a document that contains the hash of the cluster time and the ID + of the key used to sign the cluster time + +.. _rust-command-example: + +Command Example +--------------- + +The following code shows how you can use the ``command()`` method to run +the ``explain`` command for a ``count`` operation on the ``flowers`` +collection of the ``plants`` database. The ``explain`` command runs in the +``"queryPlanner"`` verbosity mode: + +.. literalinclude:: /includes/write/run-command.php + :language: php + :dedent: + :start-after: start-runcommand + :end-before: end-runcommand + +Output +~~~~~~ + +The output includes fields explaining the +execution of the ``count`` operation, such as the winning plan, which is +the plan selected by the query optimizer, and any rejected +plans. The output also contains information about the execution of the +``explain`` command: + +.. code-block:: json + :emphasize-lines: + + string(1203) + "[{"explainVersion":"1","queryPlanner":{"namespace":"plants.flowers", + "indexFilterSet":false,"maxIndexedOrSolutionsReached":false, + "maxIndexedAndSolutionsReached":false,"maxScansToExplodeReached":false,"winningPlan": + {"stage":"RECORD_STORE_FAST_COUNT"},"rejectedPlans":[]},"command":{"count":"flowers", + "$db":"plants"},"serverInfo":{"host":"...","port":27017,"version":"7.0.12", + "gitVersion":"..."},"serverParameters":{...},"ok":1,"$clusterTime":{...},"signature":{...}, + "keyId":...}},"operationTime":{"$timestamp":{"t":1725637892,"i":12}}}]" + +.. _php-addtl-info-runcommand: + +Additional Information +---------------------- + +For more information about the concepts in this guide, see the following +documentation in the Server manual: + +- :manual:`db.runCommand() ` +- :manual:`Database Commands ` +- :manual:`hello Command ` +- :manual:`explain Command ` + +API Documentation +~~~~~~~~~~~~~~~~~ + +- `MongoDB\\Database::command() <{+api+}/method/MongoDBDatabase-command/>`__ From 954c3d2738ef76ecc43137cbcd7a0eb55e58ca7d Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 6 Sep 2024 11:57:22 -0400 Subject: [PATCH 118/149] wip --- source/write/run-command.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/write/run-command.txt b/source/write/run-command.txt index e7b8a4b9..59382d2c 100644 --- a/source/write/run-command.txt +++ b/source/write/run-command.txt @@ -149,7 +149,7 @@ plans. The output also contains information about the execution of the ``explain`` command: .. code-block:: json - :emphasize-lines: + :emphasize-lines: 2, 5-6 string(1203) "[{"explainVersion":"1","queryPlanner":{"namespace":"plants.flowers", From 832a457b45cc86de44271951a87fceb495234638 Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 6 Sep 2024 11:58:51 -0400 Subject: [PATCH 119/149] formatting fix --- source/write/run-command.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/write/run-command.txt b/source/write/run-command.txt index 59382d2c..7d1168c6 100644 --- a/source/write/run-command.txt +++ b/source/write/run-command.txt @@ -71,7 +71,10 @@ parameters, see the :ref:`Additional Information section .. code-block:: php $readPref = new MongoDB\Driver\ReadPreference('primaryPreferred'); - $result = $database->command(['ping' => 1], ['readPreference' => $readPref]); + $result = $database->command( + ['ping' => 1], + ['readPreference' => $readPref] + ); For more information on read preference options, see :manual:`Read Preference ` in the Server manual. @@ -148,7 +151,7 @@ the plan selected by the query optimizer, and any rejected plans. The output also contains information about the execution of the ``explain`` command: -.. code-block:: json +.. code-block:: none :emphasize-lines: 2, 5-6 string(1203) From b6495a058a0621a94b3d6b830b2eaf144974662f Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 6 Sep 2024 12:50:56 -0400 Subject: [PATCH 120/149] JS PR fixes 1 --- source/write/run-command.txt | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/source/write/run-command.txt b/source/write/run-command.txt index 7d1168c6..140e14fc 100644 --- a/source/write/run-command.txt +++ b/source/write/run-command.txt @@ -47,12 +47,12 @@ parameters in a command document, then pass the command document to the ``command()`` method. This method returns a ``Cursor`` object. The following code shows how you can use the ``command()`` -method to run the ``hello`` command, which returns information about -the current member's role in the replica set, on a database: +method on a database to run the ``hello`` command, which returns +information about the current member's role in the replica set: .. code-block:: php - $result = $database->command(['ping' => 1]); + $result = $database->command(['hello' => 1]); To find a link to a full list of database commands and corresponding parameters, see the :ref:`Additional Information section @@ -77,7 +77,7 @@ parameters, see the :ref:`Additional Information section ); For more information on read preference options, see :manual:`Read - Preference ` in the Server manual. + Preference ` in the {+mdb-server+} manual. .. _php-command-response: @@ -109,12 +109,9 @@ response contains a document with the following fields: * - ``operationTime`` - The logical time of the operation. MongoDB uses the - logical time to order operations. - - .. seealso:: - - To learn more about logical time, see our blog post about the - :website:`Global Logical Clock `. + logical time to order operations. To learn more about this + concept, see our blog post about the :website:`Global Logical + Clock `. * - ``$clusterTime`` - A document that contains the signed cluster time. Cluster time is a @@ -126,15 +123,14 @@ response contains a document with the following fields: - ``signature``, a document that contains the hash of the cluster time and the ID of the key used to sign the cluster time -.. _rust-command-example: +.. _php-command-example: Command Example --------------- -The following code shows how you can use the ``command()`` method to run -the ``explain`` command for a ``count`` operation on the ``flowers`` -collection of the ``plants`` database. The ``explain`` command runs in the -``"queryPlanner"`` verbosity mode: +The following example uses the ``command()`` method to run +the ``explain`` command for a ``count`` operation. The ``explain`` +command runs in the ``queryPlanner`` verbosity mode: .. literalinclude:: /includes/write/run-command.php :language: php @@ -142,10 +138,7 @@ collection of the ``plants`` database. The ``explain`` command runs in the :start-after: start-runcommand :end-before: end-runcommand -Output -~~~~~~ - -The output includes fields explaining the +The output of this command includes fields explaining the execution of the ``count`` operation, such as the winning plan, which is the plan selected by the query optimizer, and any rejected plans. The output also contains information about the execution of the @@ -169,7 +162,7 @@ Additional Information ---------------------- For more information about the concepts in this guide, see the following -documentation in the Server manual: +documentation in the {+mdb-server+} manual: - :manual:`db.runCommand() ` - :manual:`Database Commands ` @@ -180,3 +173,4 @@ API Documentation ~~~~~~~~~~~~~~~~~ - `MongoDB\\Database::command() <{+api+}/method/MongoDBDatabase-command/>`__ +- `ReadPreference `__ From 2dcacc080989867c495d9d0a0de7fb85fd7c88ed Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 6 Sep 2024 12:55:37 -0400 Subject: [PATCH 121/149] link fix --- source/write/run-command.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/write/run-command.txt b/source/write/run-command.txt index 140e14fc..79cbe913 100644 --- a/source/write/run-command.txt +++ b/source/write/run-command.txt @@ -173,4 +173,4 @@ API Documentation ~~~~~~~~~~~~~~~~~ - `MongoDB\\Database::command() <{+api+}/method/MongoDBDatabase-command/>`__ -- `ReadPreference `__ +- `MongoDB\\Driver\\ReadPreference `__ From ea882c238d9e9fe59e2f8d5515e5aac83562f580 Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 6 Sep 2024 13:15:03 -0400 Subject: [PATCH 122/149] style fixes --- source/write/run-command.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/source/write/run-command.txt b/source/write/run-command.txt index 79cbe913..1e7a6b08 100644 --- a/source/write/run-command.txt +++ b/source/write/run-command.txt @@ -44,7 +44,8 @@ Execute a Command To run a database command, you must specify the command and any relevant parameters in a command document, then pass the command document to the -``command()`` method. This method returns a ``Cursor`` object. +``MongoDB\Database::command()`` method. This method returns a +``Cursor`` object. The following code shows how you can use the ``command()`` method on a database to run the ``hello`` command, which returns @@ -172,5 +173,13 @@ documentation in the {+mdb-server+} manual: API Documentation ~~~~~~~~~~~~~~~~~ +For more information about the ``command()`` method, see the +following {+php-library+} API documentation: + - `MongoDB\\Database::command() <{+api+}/method/MongoDBDatabase-command/>`__ -- `MongoDB\\Driver\\ReadPreference `__ + +For more information about the ``MongoDB\Driver\ReadPreference`` class, +see the following {+extension-short+} API documentation: + +- `MongoDB\\Driver\\ReadPreference + `__ From 13e1c13ad1e8869150f7a4ead62d17d1c00d6383 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 9 Sep 2024 13:21:59 -0400 Subject: [PATCH 123/149] JT tech review 1 --- source/includes/write/run-command.php | 14 ++++----- source/write/run-command.txt | 42 ++++++++++++--------------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/source/includes/write/run-command.php b/source/includes/write/run-command.php index eeff43cd..dacde439 100644 --- a/source/includes/write/run-command.php +++ b/source/includes/write/run-command.php @@ -4,16 +4,14 @@ use MongoDB\Client; -$client = new Client(''); +$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your Atlas URI that connects to the sample dataset'); +$client = new MongoDB\Client($uri); // start-runcommand -$database = $client->plants; +$database = $client->accounts; +$command = ['dbStats' => 1]; -$countCommand = ['count' => 'flowers']; -$explainCommand = ['explain' => $countCommand, 'verbosity' => 'queryPlanner']; - -$result = $database->command($explainCommand); +$result = $database->command($command); // end-runcommand -var_dump($result->toArray()); - +var_dump(json_encode($result->toArray())); diff --git a/source/write/run-command.txt b/source/write/run-command.txt index 1e7a6b08..66191158 100644 --- a/source/write/run-command.txt +++ b/source/write/run-command.txt @@ -48,11 +48,13 @@ parameters in a command document, then pass the command document to the ``Cursor`` object. The following code shows how you can use the ``command()`` -method on a database to run the ``hello`` command, which returns -information about the current member's role in the replica set: +method on a ``MongoDB\Driver\Database`` instance to run the ``hello`` +command, which returns information about the current member's role in +the replica set: .. code-block:: php + $database = $client->selectDatabase(''); $result = $database->command(['hello' => 1]); To find a link to a full list of database commands and corresponding @@ -61,10 +63,9 @@ parameters, see the :ref:`Additional Information section .. note:: Read Preference - The ``command()`` method does not - obey the read preference you might have set on your ``Database`` - instance elsewhere in your code. By default, ``command()`` uses the ``primary`` - read preference. + The ``command()`` method does not obey the read preference you might + have set on your ``Database`` instance elsewhere in your code. By + default, ``command()`` uses the ``primary`` read preference. You can set a read preference for command execution by setting one in the options parameter, as shown in the following code: @@ -130,8 +131,8 @@ Command Example --------------- The following example uses the ``command()`` method to run -the ``explain`` command for a ``count`` operation. The ``explain`` -command runs in the ``queryPlanner`` verbosity mode: +the ``dbStats`` command to retrieve storage statistics for the +``accounts`` database: .. literalinclude:: /includes/write/run-command.php :language: php @@ -139,23 +140,14 @@ command runs in the ``queryPlanner`` verbosity mode: :start-after: start-runcommand :end-before: end-runcommand -The output of this command includes fields explaining the -execution of the ``count`` operation, such as the winning plan, which is -the plan selected by the query optimizer, and any rejected -plans. The output also contains information about the execution of the -``explain`` command: +The output of this command includes information about the collections in +the database and describes the amount and size of data stored across +collections: .. code-block:: none - :emphasize-lines: 2, 5-6 - string(1203) - "[{"explainVersion":"1","queryPlanner":{"namespace":"plants.flowers", - "indexFilterSet":false,"maxIndexedOrSolutionsReached":false, - "maxIndexedAndSolutionsReached":false,"maxScansToExplodeReached":false,"winningPlan": - {"stage":"RECORD_STORE_FAST_COUNT"},"rejectedPlans":[]},"command":{"count":"flowers", - "$db":"plants"},"serverInfo":{"host":"...","port":27017,"version":"7.0.12", - "gitVersion":"..."},"serverParameters":{...},"ok":1,"$clusterTime":{...},"signature":{...}, - "keyId":...}},"operationTime":{"$timestamp":{"t":1725637892,"i":12}}}]" + string(234) + "[{"db":"accounts","collections":2,"views":0,"objects":5,"avgObjSize":22,"dataSize":110,"storageSize":8192,"totalFreeStorageSize":0,"numExtents":0,"indexes":2,"indexSize":8192,"indexFreeStorageSize":0,"fileSize":0,"nsSizeMB":0,"ok":1}]" .. _php-addtl-info-runcommand: @@ -168,7 +160,7 @@ documentation in the {+mdb-server+} manual: - :manual:`db.runCommand() ` - :manual:`Database Commands ` - :manual:`hello Command ` -- :manual:`explain Command ` +- :manual:`dbStats Command ` API Documentation ~~~~~~~~~~~~~~~~~ @@ -178,8 +170,10 @@ following {+php-library+} API documentation: - `MongoDB\\Database::command() <{+api+}/method/MongoDBDatabase-command/>`__ -For more information about the ``MongoDB\Driver\ReadPreference`` class, +For more information about the ``Cursor`` and ``ReadPreference`` classes, see the following {+extension-short+} API documentation: +- `MongoDB\\Driver\\Cursor + `__ - `MongoDB\\Driver\\ReadPreference `__ From 47d371759ac3f5b8422198411676edf0aaac9233 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 9 Sep 2024 13:24:23 -0400 Subject: [PATCH 124/149] wip --- source/write/run-command.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/write/run-command.txt b/source/write/run-command.txt index 66191158..fc88a822 100644 --- a/source/write/run-command.txt +++ b/source/write/run-command.txt @@ -74,7 +74,7 @@ parameters, see the :ref:`Additional Information section $readPref = new MongoDB\Driver\ReadPreference('primaryPreferred'); $result = $database->command( - ['ping' => 1], + ['hello' => 1], ['readPreference' => $readPref] ); @@ -146,8 +146,9 @@ collections: .. code-block:: none - string(234) - "[{"db":"accounts","collections":2,"views":0,"objects":5,"avgObjSize":22,"dataSize":110,"storageSize":8192,"totalFreeStorageSize":0,"numExtents":0,"indexes":2,"indexSize":8192,"indexFreeStorageSize":0,"fileSize":0,"nsSizeMB":0,"ok":1}]" + string(234) "[{"db":"accounts","collections":2,"views":0,"objects":5,"avgObjSize":22, + "dataSize":110,"storageSize":8192,"totalFreeStorageSize":0,"numExtents":0,"indexes":2, + "indexSize":8192,"indexFreeStorageSize":0,"fileSize":0,"nsSizeMB":0,"ok":1}]" .. _php-addtl-info-runcommand: From b5da5ab61972d51c4a254ec389332082f6fc9f48 Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 25 Sep 2024 15:13:32 -0400 Subject: [PATCH 125/149] JM tech review --- source/includes/write/run-command.php | 23 ++++++-- source/write/run-command.txt | 84 +++++++++++++++------------ 2 files changed, 66 insertions(+), 41 deletions(-) diff --git a/source/includes/write/run-command.php b/source/includes/write/run-command.php index dacde439..d074c337 100644 --- a/source/includes/write/run-command.php +++ b/source/includes/write/run-command.php @@ -4,14 +4,29 @@ use MongoDB\Client; -$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your Atlas URI that connects to the sample dataset'); +$uri = getenv('MONGODB_URI') ?: throw new RuntimeException('Set the MONGODB_URI variable to your connection URI'); $client = new MongoDB\Client($uri); +// start-hello +$database = $client->selectDatabase('myDB'); +$cursor = $database->command(['hello' => 1]); +// end-hello + +// start-readpref +$readPref = new MongoDB\Driver\ReadPreference('primaryPreferred'); +$cursor = $database->command( + ['hello' => 1], + ['readPreference' => $readPref] +); +// end-readpref + // start-runcommand $database = $client->accounts; $command = ['dbStats' => 1]; -$result = $database->command($command); -// end-runcommand +// dbStats returns a single document +$cursor = $database->command($command); -var_dump(json_encode($result->toArray())); +// Print the first document in the cursor +echo json_encode($cursor->toArray()[0]), PHP_EOL; +// end-runcommand diff --git a/source/write/run-command.txt b/source/write/run-command.txt index fc88a822..986ac21a 100644 --- a/source/write/run-command.txt +++ b/source/write/run-command.txt @@ -32,10 +32,11 @@ statistics, initializing a replica set, or running an aggregation pipeline. commands when possible. To perform administrative tasks, use the :mongosh:`MongoDB Shell ` - instead of the {+php-library+}. Calling the ``db.runCommand()`` - method inside the shell is the preferred way to issue database - commands, as it provides a consistent interface between the shell and - drivers or libraries. + instead of the {+php-library+}. The shell provides helper methods + that might not be available in the library. + + If there are no available helpers in the library or the shell, you + can use the ``db.runCommand()`` shell method. .. _php-execute-command: @@ -44,18 +45,20 @@ Execute a Command To run a database command, you must specify the command and any relevant parameters in a command document, then pass the command document to the -``MongoDB\Database::command()`` method. This method returns a -``Cursor`` object. +``MongoDB\Database::command()`` method. Many database commands return +multiple result documents, so the ``command()`` method returns a +``Cursor`` object that you can iterate through. The following code shows how you can use the ``command()`` -method on a ``MongoDB\Driver\Database`` instance to run the ``hello`` +method on a :phpclass:`MongoDB\Database` instance to run the ``hello`` command, which returns information about the current member's role in the replica set: -.. code-block:: php - - $database = $client->selectDatabase(''); - $result = $database->command(['hello' => 1]); +.. literalinclude:: /includes/write/run-command.php + :language: php + :dedent: + :start-after: start-hello + :end-before: end-hello To find a link to a full list of database commands and corresponding parameters, see the :ref:`Additional Information section @@ -70,13 +73,11 @@ parameters, see the :ref:`Additional Information section You can set a read preference for command execution by setting one in the options parameter, as shown in the following code: - .. code-block:: php - - $readPref = new MongoDB\Driver\ReadPreference('primaryPreferred'); - $result = $database->command( - ['hello' => 1], - ['readPreference' => $readPref] - ); + .. literalinclude:: /includes/write/run-command.php + :language: php + :dedent: + :start-after: start-readpref + :end-before: end-readpref For more information on read preference options, see :manual:`Read Preference ` in the {+mdb-server+} manual. @@ -87,11 +88,25 @@ Response -------- The ``command()`` method returns a ``Cursor`` object that contains -the response from the database after the command has been executed. - -Each database command performs a different function, so the response -content can vary depending on the command executed. However, every -response contains a document with the following fields: +the response from the database for the given command. Each database +command performs a different function, so the response +content can vary. Some command responses contain multiple result +documents. In these situations, the library converts the cursor +envelope in the raw command response, which includes the cursor ID and +the first batch of results, into an iterable cursor. + +Before you run a command, learn about the response format of the +command so that your application either iterates through multiple +results or extracts the first and only document in the cursor. See the +:ref:`php-addtl-info-runcommand` section of this guide to find a link to +the full list of database commands. + +If the number of documents in the command response is sufficiently large, you +can run a :manual:`getMore ` command to +retrieve the next batch of results from the cursor by using the cursor +ID. + +The raw command response contains the following fields: .. list-table:: :header-rows: 1 @@ -102,29 +117,24 @@ response contains a document with the following fields: * - - Fields specific to the database command. For example, - ``count`` returns the ``n`` field and ``explain`` returns the - ``queryPlanner`` field. + the ``count`` command returns the ``n`` field. * - ``ok`` - - Whether the command has succeeded (``1``) - or failed (``0``). + - Whether the command has succeeded (``1``) or failed (``0``). The + library raises a :php:`CommandException + ` if + the ``ok`` field is ``0``. * - ``operationTime`` - The logical time of the operation. MongoDB uses the logical time to order operations. To learn more about this - concept, see our blog post about the :website:`Global Logical + concept, see our blog post about the :website:`Global Logical Clock `. * - ``$clusterTime`` - A document that contains the signed cluster time. Cluster time is a logical time used for the ordering of operations. - This document contains the following fields: - - - ``clusterTime``, the timestamp of the highest known cluster time for the member - - ``signature``, a document that contains the hash of the cluster time and the ID - of the key used to sign the cluster time - .. _php-command-example: Command Example @@ -146,9 +156,9 @@ collections: .. code-block:: none - string(234) "[{"db":"accounts","collections":2,"views":0,"objects":5,"avgObjSize":22, - "dataSize":110,"storageSize":8192,"totalFreeStorageSize":0,"numExtents":0,"indexes":2, - "indexSize":8192,"indexFreeStorageSize":0,"fileSize":0,"nsSizeMB":0,"ok":1}]" + {"db":"accounts","collections":2,"views":0,"objects":5,"avgObjSize":22,"dataSize":110, + "storageSize":40960,"totalFreeStorageSize":0,"numExtents":0,"indexes":2,"indexSize":40960, + "indexFreeStorageSize":0,"fileSize":0,"nsSizeMB":0,"ok":1} .. _php-addtl-info-runcommand: From 3e0710d2712612cd617e0fa5f3ad4520d2e766fe Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 25 Sep 2024 15:16:39 -0400 Subject: [PATCH 126/149] tree --- source/index.txt | 6 ++++++ source/{write => }/run-command.txt | 0 2 files changed, 6 insertions(+) rename source/{write => }/run-command.txt (100%) diff --git a/source/index.txt b/source/index.txt index f8d9c36f..cd3e5d2a 100644 --- a/source/index.txt +++ b/source/index.txt @@ -16,6 +16,7 @@ MongoDB PHP Library /read /write /read-write-pref + /run-command /aggregation /indexes /monitoring @@ -68,6 +69,11 @@ Write Data to MongoDB Learn how you can write data to MongoDB in the :ref:`php-write` section. +Run a Database Command +---------------------- + +Learn how to run a database command in the :ref:`php-run-command` section. + Transform Your Data with Aggregation ------------------------------------ diff --git a/source/write/run-command.txt b/source/run-command.txt similarity index 100% rename from source/write/run-command.txt rename to source/run-command.txt From b77281b38e836408e0a3b8313a8bc5b5a5bb140d Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 25 Sep 2024 15:17:50 -0400 Subject: [PATCH 127/149] api links --- source/run-command.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/run-command.txt b/source/run-command.txt index 986ac21a..dd197972 100644 --- a/source/run-command.txt +++ b/source/run-command.txt @@ -179,12 +179,10 @@ API Documentation For more information about the ``command()`` method, see the following {+php-library+} API documentation: -- `MongoDB\\Database::command() <{+api+}/method/MongoDBDatabase-command/>`__ +:phpmethod:`MongoDB\Database::command()` For more information about the ``Cursor`` and ``ReadPreference`` classes, see the following {+extension-short+} API documentation: -- `MongoDB\\Driver\\Cursor - `__ -- `MongoDB\\Driver\\ReadPreference - `__ +- :php:`MongoDB\Driver\Cursor ` +- :php:`MongoDB\Driver\ReadPreference ` From b08b7bf700e64a9d793fa0cc0fa8df1aaf846962 Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 25 Sep 2024 15:34:46 -0400 Subject: [PATCH 128/149] links --- source/run-command.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/run-command.txt b/source/run-command.txt index dd197972..c82962c1 100644 --- a/source/run-command.txt +++ b/source/run-command.txt @@ -184,5 +184,5 @@ following {+php-library+} API documentation: For more information about the ``Cursor`` and ``ReadPreference`` classes, see the following {+extension-short+} API documentation: -- :php:`MongoDB\Driver\Cursor ` -- :php:`MongoDB\Driver\ReadPreference ` +- :php:`MongoDB\Driver\Cursor ` +- :php:`MongoDB\Driver\ReadPreference ` From 8918fbf7e43f53f1733176fd9ac6524e4e91ab39 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 26 Sep 2024 15:06:38 -0400 Subject: [PATCH 129/149] JM tech review 2 --- source/run-command.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/run-command.txt b/source/run-command.txt index c82962c1..0b75a095 100644 --- a/source/run-command.txt +++ b/source/run-command.txt @@ -36,7 +36,9 @@ statistics, initializing a replica set, or running an aggregation pipeline. that might not be available in the library. If there are no available helpers in the library or the shell, you - can use the ``db.runCommand()`` shell method. + can use the ``db.runCommand()`` shell method or the library's + ``MongoDB\Database::command()`` method, which is described in this + guide. .. _php-execute-command: @@ -47,12 +49,11 @@ To run a database command, you must specify the command and any relevant parameters in a command document, then pass the command document to the ``MongoDB\Database::command()`` method. Many database commands return multiple result documents, so the ``command()`` method returns a -``Cursor`` object that you can iterate through. +``MongoDB\Driver\Cursor`` object that you can iterate through. The following code shows how you can use the ``command()`` method on a :phpclass:`MongoDB\Database` instance to run the ``hello`` -command, which returns information about the current member's role in -the replica set: +command, which returns information about the server: .. literalinclude:: /includes/write/run-command.php :language: php @@ -66,7 +67,7 @@ parameters, see the :ref:`Additional Information section .. note:: Read Preference - The ``command()`` method does not obey the read preference you might + The ``command()`` method does not inherit the read preference you might have set on your ``Database`` instance elsewhere in your code. By default, ``command()`` uses the ``primary`` read preference. @@ -90,8 +91,12 @@ Response The ``command()`` method returns a ``Cursor`` object that contains the response from the database for the given command. Each database command performs a different function, so the response -content can vary. Some command responses contain multiple result -documents. In these situations, the library converts the cursor +content can vary. + +For commands that return a single result document, +that result is available as the first and only document in the +cursor. For commands that return multiple result +documents, the library converts the cursor envelope in the raw command response, which includes the cursor ID and the first batch of results, into an iterable cursor. @@ -101,11 +106,6 @@ results or extracts the first and only document in the cursor. See the :ref:`php-addtl-info-runcommand` section of this guide to find a link to the full list of database commands. -If the number of documents in the command response is sufficiently large, you -can run a :manual:`getMore ` command to -retrieve the next batch of results from the cursor by using the cursor -ID. - The raw command response contains the following fields: .. list-table:: From 5053786d2462dfd080e43e6b394343d259ef5fd9 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 26 Sep 2024 15:15:19 -0400 Subject: [PATCH 130/149] small fixes --- source/run-command.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/source/run-command.txt b/source/run-command.txt index 0b75a095..96d564ba 100644 --- a/source/run-command.txt +++ b/source/run-command.txt @@ -49,7 +49,8 @@ To run a database command, you must specify the command and any relevant parameters in a command document, then pass the command document to the ``MongoDB\Database::command()`` method. Many database commands return multiple result documents, so the ``command()`` method returns a -``MongoDB\Driver\Cursor`` object that you can iterate through. +:php:`MongoDB\Driver\Cursor ` object that you can +iterate through. The following code shows how you can use the ``command()`` method on a :phpclass:`MongoDB\Database` instance to run the ``hello`` @@ -80,7 +81,11 @@ parameters, see the :ref:`Additional Information section :start-after: start-readpref :end-before: end-readpref - For more information on read preference options, see :manual:`Read + Learn more about the ``ReadPreference`` class in the + :php:`{+extension-short+} API documentation + `. + + To learn more about read preference options, see :manual:`Read Preference ` in the {+mdb-server+} manual. .. _php-command-response: @@ -179,10 +184,4 @@ API Documentation For more information about the ``command()`` method, see the following {+php-library+} API documentation: -:phpmethod:`MongoDB\Database::command()` - -For more information about the ``Cursor`` and ``ReadPreference`` classes, -see the following {+extension-short+} API documentation: - -- :php:`MongoDB\Driver\Cursor ` -- :php:`MongoDB\Driver\ReadPreference ` +- :phpmethod:`MongoDB\Database::command()` From 9a7aa0849d5dc671dae64e92de1d3b876235824c Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 26 Sep 2024 15:15:40 -0400 Subject: [PATCH 131/149] add ext upgrade command --- source/upgrade.txt | 64 ++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index dbd3a41b..1121eb18 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -43,15 +43,28 @@ Before you upgrade, perform the following actions: To ensure compatibility across {+mdb-server+} versions when upgrading driver versions, use the :ref:`{+stable-api+} `. -To upgrade your driver version, replace ```` with the version number +Major and minor versions of the PHP extension and library are in sync. This +means you can run an upgrade command for the extension to also upgrade the PHP +library. + +Patch versions (x.x.x) for the library and extension are not in sync. Run the +respective commands to update to the patch versions for the library or extension. + +To upgrade the PHP extension, replace ```` with the version number you want to upgrade to and run the following command in your application's directory: +.. code-block:: bash + + pecl upgrade mongodb- + +To upgrade the PHP Library version, use the following command: + .. code-block:: bash composer require mongodb/mongodb: -Installation instructions for the ``mongodb`` extension may be found in the +Detailed installation instructions may be found in the :php:`PHP.net documentation `. .. _php-breaking-changes: @@ -77,47 +90,8 @@ This driver version introduces the following breaking changes: - Drops support for {+mdb-server+} 3.6. -- Deprecates iterators for database, collection, and index enumeration. - -Version 1.18 Breaking Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This driver version introduces the following breaking changes: - -- Deprecates setting ``disableMD5`` to ``false`` when instantiating a Bucket due to - deprecated MD5 encoding. The default value for the setting is now ``true``. - -Version 1.17 Breaking Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This driver version introduces the following breaking changes: - -- Upgrades the ``mongodb`` extension requirement to 1.17.0. - -- Requires PHP 7.4 or newer. - -- Removes aggregate compatibility logic, like the ``useCursor`` option, for - {+mdb-server+} versions less than 3.6. - -Version 1.16 Breaking Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This driver version introduces the following breaking changes: - -- Upgrades the ``mongodb`` extension requirement to 1.16.0. - -- Deprecates ``IndexInfo::isGeoHaystack()``. ``geoHaystack`` was removed in - {+mdb-server+} 5.0 and later. - -- Drops support for Composer 1.x. - -- Removes ``$server`` argument in ``Explainable::getCommandDocument``. - -- Removes ``getNonce`` command usage for {+mdb-server+} 6.2 and later. - -Version 1.15 Breaking Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This driver version introduces the following breaking changes: +Version 1.19 and Earlier +~~~~~~~~~~~~~~~~~~~~~~~~ -- Upgrades the ``mongodb`` extension requirement to 1.15.0. +For driver versions 1.19 and earlier, see the release notes and associated +JIRA tickets for each release on `GitHub `__. From fcc573617ec1f3d57b9d2ba06e16f20aa67a47bd Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 12:55:48 -0400 Subject: [PATCH 132/149] DOCSP-41995: transaction --- snooty.toml | 1 + source/includes/write/transaction.php | 52 ++++++++ source/write.txt | 1 + source/write/transaction.txt | 168 ++++++++++++++++++++++++++ 4 files changed, 222 insertions(+) create mode 100644 source/includes/write/transaction.php create mode 100644 source/write/transaction.txt diff --git a/snooty.toml b/snooty.toml index d2d18efa..2c74c607 100644 --- a/snooty.toml +++ b/snooty.toml @@ -44,3 +44,4 @@ stable-api = "Stable API" library-short = "PHP library" api = "https://www.mongodb.com/docs/php-library/current/reference" php-manual = "https://www.php.net/manual/en" +extension-short = "PHP extension" \ No newline at end of file diff --git a/source/includes/write/transaction.php b/source/includes/write/transaction.php new file mode 100644 index 00000000..ace53c26 --- /dev/null +++ b/source/includes/write/transaction.php @@ -0,0 +1,52 @@ +bank->receipts; +$checking = $client->bank->checking_accounts; +$saving = $client->bank->saving_accounts; + +$accountId = '5678'; +$transferAmount = 1000.00; + +$callback = function (MongoDB\Driver\Session $session) + use ($checking, $saving, $receipts, $accountId, $transferAmount): void { + + $checking->updateOne( + ['account_id' => $accountId], + ['$inc' => ['balance' => -$transferAmount]], + ['session' => $session] + ); + + $saving->updateOne( + ['account_id' => $accountId], + ['$inc' => ['balance' => $transferAmount]], + ['session' => $session] + ); + + $summary = sprintf( + "SAVINGS +%u CHECKING -%u.", $transferAmount, $transferAmount + ); + + $receipts->insertOne([ + 'account_id' => $accountId, + 'description' => $summary, + 'timestamp' => new MongoDB\BSON\UTCDateTime((new DateTime())->getTimestamp()*1000), + ], ['session' => $session]); + + echo 'Successfully performed transaction!\n'; +}; +// end-callback + +// begin-txn +$session = $client->startSession(); + +try { + MongoDB\with_transaction($session, $callback); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), '\n'; +} +// end-txn \ No newline at end of file diff --git a/source/write.txt b/source/write.txt index ee30d336..8d9d16ca 100644 --- a/source/write.txt +++ b/source/write.txt @@ -27,6 +27,7 @@ Write Data to MongoDB /write/delete /write/replace /write/bulk-write + /write/transaction /write/gridfs Overview diff --git a/source/write/transaction.txt b/source/write/transaction.txt new file mode 100644 index 00000000..8056b88d --- /dev/null +++ b/source/write/transaction.txt @@ -0,0 +1,168 @@ +.. _php-transactions: + +===================== +Perform a Transaction +===================== + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, ACID compliance, multi-document + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +In this guide, you can learn how to use the {+driver-short+} to perform +**transactions**. Transactions allow you to perform a series of operations +that change data only if the entire transaction is committed. +If any operation in the transaction does not succeed, the driver stops the +transaction and discards all data changes before they ever become +visible. This feature is called **atomicity**. + +In MongoDB, transactions run within logical sessions. A +session is a grouping of related read or write operations that you +want to run sequentially. Sessions enable causal consistency for a group +of operations and allow you to run operations in an **ACID-compliant** +transaction, which is a transaction that meets an expectation of +atomicity, consistency, isolation, and durability. MongoDB guarantees +that the data involved in your transaction operations remains +consistent, even if the operations encounter unexpected errors. + +When using the {+php-library+}, you can create a new session from a +``MongoDB\Client`` instance. Then, you can use the resulting +``MongoDB\Driver\Session`` instance to perform transactions. You can +improve your app's performance by reusing your client for multiple +sessions and transactions instead of instantiating a new client each +time. + +.. warning:: + + Use a ``Session`` only in operations running on the + ``Client`` that created it. Using a ``Session`` with a + different ``Client`` results in operation errors. + +Methods +------- + +Create a ``Session`` by using the ``MongoDB\Client::startSession()`` +method on your ``Client`` instance. The {+php-library+} provides a +Convenient Transaction API to manage the transaction lifecyle. Use the +``MongoDB\with_transaction()`` method to run custom callback within a +transaction. The ``with_transaction()`` method starts the transaction, +then either commits it or ends it if there are errors. The +:ref:`php-txn-example` section of this guide demonstrates how to use +this API to perform a transaction. + +Alternatively, you can have more control over your transaction lifecyle +by using the methods provided by the ``Session`` class. The +following table describes these methods: + +.. list-table:: + :widths: 25 75 + :stub-columns: 1 + :header-rows: 1 + + * - Method + - Description + + * - ``startTransaction()`` + - | Starts a new transaction on this session. The session + must be passed into each operation within the transaction, or + the operation will run outside of the transaction. + | + | You can set transaction options by passing an options parameter. + + * - ``commitTransaction()`` + - | Commits the active transaction for this session. This method returns an + error if there is no active transaction for the session or the + transaction was previously ended. + + * - ``abortTransaction()`` + - | Ends the active transaction for this session. This method returns an + error if there is no active transaction for the session or if the + transaction was committed or ended. + +.. _php-txn-example: + +Transaction Example +------------------- + +The following code defines the ``transferTxn()`` callback function that +modifies data in the ``saving_accounts``, ``checking_accounts``, and ``receipts`` +collections of the ``bank`` database: + +.. literalinclude:: /includes/write/transaction.php + :language: php + :dedent: + :start-after: begin-callback + :end-before: end-callback + +Then, run the following code to perform the transaction. This code +completes the following actions: + +1. Creates a session from the client by using the ``startSession()`` method. +#. Calls the ``with_transaction()`` method to manage the transaction, + passing the session and the callback as parameters. + +.. io-code-block:: + + .. input:: /includes/write/transaction.php + :language: php + :dedent: + :start-after: begin-txn + :end-before: end-txn + + .. output:: + :language: console + :visible: false + + Successfully committed transaction! + +Additional Information +---------------------- + +To learn more about the concepts mentioned in this guide, see the +following pages in the {+mdb-server+} manual: + +- :manual:`Transactions ` +- :manual:`Server Sessions ` +- :manual:`Read Isolation, Consistency, and Recency + ` + +To learn more about ACID compliance, see the :website:`What are ACID +Properties in Database Management Systems? ` +article on the MongoDB website. + +To learn more about insert operations, see the +:ref:`php-write-insert` guide. + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about the methods and types mentioned in this +guide, see the following API documentation: + +- :phpclass:`MongoDB\Client` +- :phpmethod:`MongoDB\Client::startSession()` +- :phpmethod:`MongoDB\Collection::updateOne()` +- :phpmethod:`MongoDB\Collection::insertOne()` + +To learn more about the ``Session`` class and methods, +see the following {+extension-short+} API documentation: + +- `MongoDB\\Driver\\Session + `__ +- `MongoDB\\Driver\\Session::abortTransaction() + `__ +- `MongoDB\\Driver\\Session::commitTransaction() + `__ +- `MongoDB\\Driver\\Session::startTransaction() + `__ From ada33fc2a7faa389a91096008ae5f16054815420 Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 13:06:48 -0400 Subject: [PATCH 133/149] wip --- source/includes/write/transaction.php | 9 +++++---- source/write/transaction.txt | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/source/includes/write/transaction.php b/source/includes/write/transaction.php index ace53c26..76e26db7 100644 --- a/source/includes/write/transaction.php +++ b/source/includes/write/transaction.php @@ -34,10 +34,11 @@ $receipts->insertOne([ 'account_id' => $accountId, 'description' => $summary, - 'timestamp' => new MongoDB\BSON\UTCDateTime((new DateTime())->getTimestamp()*1000), - ], ['session' => $session]); + 'timestamp' => new MongoDB\BSON\UTCDateTime(), + ], + ['session' => $session]); - echo 'Successfully performed transaction!\n'; + echo 'Successfully performed transaction!' , "\n"; }; // end-callback @@ -47,6 +48,6 @@ try { MongoDB\with_transaction($session, $callback); } catch (Exception $e) { - echo 'Caught exception: ', $e->getMessage(), '\n'; + echo 'Caught exception: ', $e->getMessage(), "\n"; } // end-txn \ No newline at end of file diff --git a/source/write/transaction.txt b/source/write/transaction.txt index 8056b88d..1f795f01 100644 --- a/source/write/transaction.txt +++ b/source/write/transaction.txt @@ -124,7 +124,7 @@ completes the following actions: :language: console :visible: false - Successfully committed transaction! + Successfully performed transaction! Additional Information ---------------------- From 8218890b42bd4cb9ad4e38412646f176088d2fdd Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 16:13:53 -0400 Subject: [PATCH 134/149] update code --- source/includes/write/transaction.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/includes/write/transaction.php b/source/includes/write/transaction.php index 76e26db7..f50b8dd2 100644 --- a/source/includes/write/transaction.php +++ b/source/includes/write/transaction.php @@ -33,12 +33,13 @@ $receipts->insertOne([ 'account_id' => $accountId, - 'description' => $summary, + 'summary' => $summary, 'timestamp' => new MongoDB\BSON\UTCDateTime(), ], ['session' => $session]); - echo 'Successfully performed transaction!' , "\n"; + echo 'Successfully performed transaction!' , PHP_EOL; + echo 'Summary: ', $summary, PHP_EOL; }; // end-callback From 0492a7f464940795e55a1c330fc0b0b30a2cc242 Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 16:17:59 -0400 Subject: [PATCH 135/149] NR PR fixes 1 --- snooty.toml | 2 +- source/includes/write/transaction.php | 2 +- source/write/transaction.txt | 16 +++++++++------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/snooty.toml b/snooty.toml index 2c74c607..5f676f6e 100644 --- a/snooty.toml +++ b/snooty.toml @@ -44,4 +44,4 @@ stable-api = "Stable API" library-short = "PHP library" api = "https://www.mongodb.com/docs/php-library/current/reference" php-manual = "https://www.php.net/manual/en" -extension-short = "PHP extension" \ No newline at end of file +extension-short = "PHP extension" diff --git a/source/includes/write/transaction.php b/source/includes/write/transaction.php index f50b8dd2..77a41fc2 100644 --- a/source/includes/write/transaction.php +++ b/source/includes/write/transaction.php @@ -28,7 +28,7 @@ ); $summary = sprintf( - "SAVINGS +%u CHECKING -%u.", $transferAmount, $transferAmount + "SAVINGS +%u CHECKING -%u", $transferAmount, $transferAmount ); $receipts->insertOne([ diff --git a/source/write/transaction.txt b/source/write/transaction.txt index 1f795f01..1c3bdfcc 100644 --- a/source/write/transaction.txt +++ b/source/write/transaction.txt @@ -20,10 +20,10 @@ Perform a Transaction Overview -------- -In this guide, you can learn how to use the {+driver-short+} to perform +In this guide, you can learn how to use the {+php-library+} to perform **transactions**. Transactions allow you to perform a series of operations that change data only if the entire transaction is committed. -If any operation in the transaction does not succeed, the driver stops the +If any operation in the transaction does not succeed, the library stops the transaction and discards all data changes before they ever become visible. This feature is called **atomicity**. @@ -116,6 +116,7 @@ completes the following actions: .. input:: /includes/write/transaction.php :language: php + :copyable: :dedent: :start-after: begin-txn :end-before: end-txn @@ -125,6 +126,7 @@ completes the following actions: :visible: false Successfully performed transaction! + Summary: SAVINGS +1000 CHECKING -1000 Additional Information ---------------------- @@ -135,7 +137,7 @@ following pages in the {+mdb-server+} manual: - :manual:`Transactions ` - :manual:`Server Sessions ` - :manual:`Read Isolation, Consistency, and Recency - ` + ` To learn more about ACID compliance, see the :website:`What are ACID Properties in Database Management Systems? ` @@ -159,10 +161,10 @@ To learn more about the ``Session`` class and methods, see the following {+extension-short+} API documentation: - `MongoDB\\Driver\\Session - `__ + <{+php-manual+}/class.mongodb-driver-session.php>`__ - `MongoDB\\Driver\\Session::abortTransaction() - `__ + <{+php-manual+}/mongodb-driver-session.aborttransaction.php>`__ - `MongoDB\\Driver\\Session::commitTransaction() - `__ + <{+php-manual+}/mongodb-driver-session.committransaction.php>`__ - `MongoDB\\Driver\\Session::startTransaction() - `__ + <{+php-manual+}/mongodb-driver-session.starttransaction.php>`__ From b85aed79546e4358c2556da6b5267f9bfd845750 Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 16:26:16 -0400 Subject: [PATCH 136/149] wip --- source/write/transaction.txt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/source/write/transaction.txt b/source/write/transaction.txt index 1c3bdfcc..6ed7de5a 100644 --- a/source/write/transaction.txt +++ b/source/write/transaction.txt @@ -95,11 +95,22 @@ following table describes these methods: Transaction Example ------------------- -The following code defines the ``transferTxn()`` callback function that -modifies data in the ``saving_accounts``, ``checking_accounts``, and ``receipts`` -collections of the ``bank`` database: +This example defines a callback function that +modifies data in the collections of the ``bank`` database for a +banking transaction. The code performs the following actions: + +- Creates ``Collection`` instances to access the target + collections. +- Specifies the account number and amount to be transferred between + accounts. +- Defines the callback function, passing the ``Session`` instance as a + parameter. +- Updates the customer's balances to reflect the money transfer. +- Records a receipt of the transaction with a timestamp. +- Prints a message if the transaction committed successfully. .. literalinclude:: /includes/write/transaction.php + :copyable: :language: php :dedent: :start-after: begin-callback @@ -113,10 +124,10 @@ completes the following actions: passing the session and the callback as parameters. .. io-code-block:: + :copyable: .. input:: /includes/write/transaction.php :language: php - :copyable: :dedent: :start-after: begin-txn :end-before: end-txn From 73ee986bab4b86811fb4890e0f24316c37fc961e Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 16:29:57 -0400 Subject: [PATCH 137/149] add emphasis --- source/write/transaction.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/source/write/transaction.txt b/source/write/transaction.txt index 6ed7de5a..c477b204 100644 --- a/source/write/transaction.txt +++ b/source/write/transaction.txt @@ -131,6 +131,7 @@ completes the following actions: :dedent: :start-after: begin-txn :end-before: end-txn + :emphasize-lines: 1, 4 .. output:: :language: console From f107bc9f86159e16d89391fa2a7c49677c0168b9 Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 11 Sep 2024 16:31:03 -0400 Subject: [PATCH 138/149] add with_txn() method to api links --- source/write/transaction.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/source/write/transaction.txt b/source/write/transaction.txt index c477b204..e42ab494 100644 --- a/source/write/transaction.txt +++ b/source/write/transaction.txt @@ -166,6 +166,7 @@ guide, see the following API documentation: - :phpclass:`MongoDB\Client` - :phpmethod:`MongoDB\Client::startSession()` +- :phpmethod:`MongoDB\with_transaction()` - :phpmethod:`MongoDB\Collection::updateOne()` - :phpmethod:`MongoDB\Collection::insertOne()` From 3ede497cc88a09e00bd7aedfd7f34472051d2729 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 26 Sep 2024 12:44:06 -0400 Subject: [PATCH 139/149] cxn string env --- source/includes/write/transaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/includes/write/transaction.php b/source/includes/write/transaction.php index 77a41fc2..5e7781a7 100644 --- a/source/includes/write/transaction.php +++ b/source/includes/write/transaction.php @@ -1,7 +1,7 @@ Date: Thu, 26 Sep 2024 15:20:59 -0400 Subject: [PATCH 140/149] edit --- source/upgrade.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index 1121eb18..4133eb29 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -58,7 +58,7 @@ directory: pecl upgrade mongodb- -To upgrade the PHP Library version, use the following command: +To upgrade the PHP library version, run the following command: .. code-block:: bash From 2c12b6b61e37f797d8f383b256b8fc13eaaacc8b Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 26 Sep 2024 15:33:56 -0400 Subject: [PATCH 141/149] JM tech review 1 --- source/includes/write/transaction.php | 56 +++++++++++---------- source/write/transaction.txt | 70 +++++++++++++++++---------- 2 files changed, 74 insertions(+), 52 deletions(-) diff --git a/source/includes/write/transaction.php b/source/includes/write/transaction.php index 5e7781a7..eaa73394 100644 --- a/source/includes/write/transaction.php +++ b/source/includes/write/transaction.php @@ -9,37 +9,41 @@ $checking = $client->bank->checking_accounts; $saving = $client->bank->saving_accounts; -$accountId = '5678'; -$transferAmount = 1000.00; - -$callback = function (MongoDB\Driver\Session $session) - use ($checking, $saving, $receipts, $accountId, $transferAmount): void { - +$accountId = "5678"; +$transferAmount = 1000.0; + +$callback = function (MongoDB\Driver\Session $session) use ( + $checking, + $saving, + $receipts, + $accountId, + $transferAmount +): void { $checking->updateOne( - ['account_id' => $accountId], - ['$inc' => ['balance' => -$transferAmount]], - ['session' => $session] + ["account_id" => $accountId], + ['$inc' => ["balance" => -$transferAmount]], + ["session" => $session] ); - + $saving->updateOne( - ['account_id' => $accountId], - ['$inc' => ['balance' => $transferAmount]], - ['session' => $session] + ["account_id" => $accountId], + ['$inc' => ["balance" => $transferAmount]], + ["session" => $session] ); - $summary = sprintf( - "SAVINGS +%u CHECKING -%u", $transferAmount, $transferAmount - ); + $summary = sprintf('SAVINGS +%1$u CHECKING -%1$u', $transferAmount); - $receipts->insertOne([ - 'account_id' => $accountId, - 'summary' => $summary, - 'timestamp' => new MongoDB\BSON\UTCDateTime(), - ], - ['session' => $session]); + $receipts->insertOne( + [ + "account_id" => $accountId, + "summary" => $summary, + "timestamp" => new MongoDB\BSON\UTCDateTime(), + ], + ["session" => $session] + ); - echo 'Successfully performed transaction!' , PHP_EOL; - echo 'Summary: ', $summary, PHP_EOL; + echo "Successfully performed transaction!", PHP_EOL; + echo "Summary: ", $summary, PHP_EOL; }; // end-callback @@ -48,7 +52,7 @@ try { MongoDB\with_transaction($session, $callback); -} catch (Exception $e) { - echo 'Caught exception: ', $e->getMessage(), "\n"; +} catch (MongoDB\Driver\Exception\RuntimeException $e) { + echo "Caught exception: ", $e->getMessage(), PHP_EOL; } // end-txn \ No newline at end of file diff --git a/source/write/transaction.txt b/source/write/transaction.txt index e42ab494..f5a12604 100644 --- a/source/write/transaction.txt +++ b/source/write/transaction.txt @@ -38,10 +38,7 @@ consistent, even if the operations encounter unexpected errors. When using the {+php-library+}, you can create a new session from a ``MongoDB\Client`` instance. Then, you can use the resulting -``MongoDB\Driver\Session`` instance to perform transactions. You can -improve your app's performance by reusing your client for multiple -sessions and transactions instead of instantiating a new client each -time. +``MongoDB\Driver\Session`` instance to perform transactions. .. warning:: @@ -49,18 +46,42 @@ time. ``Client`` that created it. Using a ``Session`` with a different ``Client`` results in operation errors. -Methods -------- +Transaction APIs +---------------- -Create a ``Session`` by using the ``MongoDB\Client::startSession()`` -method on your ``Client`` instance. The {+php-library+} provides a -Convenient Transaction API to manage the transaction lifecyle. Use the -``MongoDB\with_transaction()`` method to run custom callback within a -transaction. The ``with_transaction()`` method starts the transaction, -then either commits it or ends it if there are errors. The -:ref:`php-txn-example` section of this guide demonstrates how to use +In this section, you can learn about the transaction APIs provided by +the {+php-library+}. Before you begin a transaction, you must create a +``Session`` by using the ``MongoDB\Client::startSession()`` +method on your ``Client`` instance. Then, you can use either of the +following APIs to perform a transaction: + +- :ref:`php-convenient-txn` +- :ref:`php-core-txn` + +.. _php-convenient-txn: + +Convenient API +~~~~~~~~~~~~~~ + +The {+php-library+} provides a **Convenient Transaction API** to manage +the transaction lifecyle. Implement this API by using the +``MongoDB\with_transaction()`` function to run custom callback within a +transaction. The ``with_transaction()`` function performs the following +tasks: + +- Starts the transaction +- Handles errors by either ending the transaction or retrying it, such + as when the operation returns a ``TransientTransactionError`` +- Commits the transaction + +The :ref:`php-txn-example` section of this guide demonstrates how to use this API to perform a transaction. +.. _php-core-txn: + +Core API +~~~~~~~~ + Alternatively, you can have more control over your transaction lifecyle by using the methods provided by the ``Session`` class. The following table describes these methods: @@ -82,8 +103,9 @@ following table describes these methods: * - ``commitTransaction()`` - | Commits the active transaction for this session. This method returns an - error if there is no active transaction for the session or the - transaction was previously ended. + error if there is no active transaction for the session, the + transaction was previously ended, or if there is a write + conflict. * - ``abortTransaction()`` - | Ends the active transaction for this session. This method returns an @@ -103,8 +125,8 @@ banking transaction. The code performs the following actions: collections. - Specifies the account number and amount to be transferred between accounts. -- Defines the callback function, passing the ``Session`` instance as a - parameter. +- Defines the callback function, which receives the ``Session`` instance + as a parameter. - Updates the customer's balances to reflect the money transfer. - Records a receipt of the transaction with a timestamp. - Prints a message if the transaction committed successfully. @@ -120,7 +142,7 @@ Then, run the following code to perform the transaction. This code completes the following actions: 1. Creates a session from the client by using the ``startSession()`` method. -#. Calls the ``with_transaction()`` method to manage the transaction, +#. Calls the ``with_transaction()`` function to manage the transaction, passing the session and the callback as parameters. .. io-code-block:: @@ -173,11 +195,7 @@ guide, see the following API documentation: To learn more about the ``Session`` class and methods, see the following {+extension-short+} API documentation: -- `MongoDB\\Driver\\Session - <{+php-manual+}/class.mongodb-driver-session.php>`__ -- `MongoDB\\Driver\\Session::abortTransaction() - <{+php-manual+}/mongodb-driver-session.aborttransaction.php>`__ -- `MongoDB\\Driver\\Session::commitTransaction() - <{+php-manual+}/mongodb-driver-session.committransaction.php>`__ -- `MongoDB\\Driver\\Session::startTransaction() - <{+php-manual+}/mongodb-driver-session.starttransaction.php>`__ +- :php:`MongoDB\Driver\Session ` +- :php:`MongoDB\Driver\Session::abortTransaction() ` +- :php:`MongoDB\Driver\Session::commitTransaction() ` +- :php:`MongoDB\Driver\Session::startTransaction() ` From d5a8d53d89655e58ff7c9bfd0427782a4817912f Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 26 Sep 2024 15:35:09 -0400 Subject: [PATCH 142/149] remove dupe sc --- snooty.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/snooty.toml b/snooty.toml index 5f676f6e..d2d18efa 100644 --- a/snooty.toml +++ b/snooty.toml @@ -44,4 +44,3 @@ stable-api = "Stable API" library-short = "PHP library" api = "https://www.mongodb.com/docs/php-library/current/reference" php-manual = "https://www.php.net/manual/en" -extension-short = "PHP extension" From 36b360c208b0df8139eb2b85ca9c203cb17a0cc9 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Thu, 26 Sep 2024 16:06:45 -0400 Subject: [PATCH 143/149] tech review --- source/includes/usage-examples/read-code-examples.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/includes/usage-examples/read-code-examples.php b/source/includes/usage-examples/read-code-examples.php index 8b73bc15..e6203cdf 100644 --- a/source/includes/usage-examples/read-code-examples.php +++ b/source/includes/usage-examples/read-code-examples.php @@ -43,7 +43,7 @@ // Distinct Values // start-distinct -$results = $collection->distinct('year', []); +$results = $collection->distinct('year'); foreach ($results as $value) { echo json_encode($value) . PHP_EOL; } @@ -64,4 +64,4 @@ break; } } -// end-change-stream \ No newline at end of file +// end-change-stream From baf5e1324d3d241bd7a80b8129b2617c21733c97 Mon Sep 17 00:00:00 2001 From: rustagir Date: Fri, 27 Sep 2024 10:40:01 -0400 Subject: [PATCH 144/149] wrap fix --- source/write/transaction.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/write/transaction.txt b/source/write/transaction.txt index f5a12604..342be0e4 100644 --- a/source/write/transaction.txt +++ b/source/write/transaction.txt @@ -104,8 +104,7 @@ following table describes these methods: * - ``commitTransaction()`` - | Commits the active transaction for this session. This method returns an error if there is no active transaction for the session, the - transaction was previously ended, or if there is a write - conflict. + transaction was previously ended, or if there is a write conflict. * - ``abortTransaction()`` - | Ends the active transaction for this session. This method returns an From f03e46ce06860c4a1b87f8affc6e5b794ad92616 Mon Sep 17 00:00:00 2001 From: Lindsey Moore Date: Fri, 27 Sep 2024 11:50:17 -0400 Subject: [PATCH 145/149] edit copy --- source/upgrade.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/upgrade.txt b/source/upgrade.txt index 4133eb29..aab0d18d 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -58,7 +58,9 @@ directory: pecl upgrade mongodb- -To upgrade the PHP library version, run the following command: +To upgrade the PHP library version, replace ```` with the +version number you want to upgrade to and run the following command in your +application's directory: .. code-block:: bash From cf2b492980e11919b341b8c9874d11a212e87f65 Mon Sep 17 00:00:00 2001 From: Mike Woofter <108414937+mongoKart@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:52:20 -0500 Subject: [PATCH 146/149] DOCSP-41959 - Connection Options (#112) Co-authored-by: Nora Reidy Co-authored-by: Jeremy Mikola --- snooty.toml | 7 +- source/connect.txt | 4 +- source/connect/connection-options.txt | 328 ++++++++++++++++++ .../includes/connect/connection-options.php | 22 ++ source/reference/class/MongoDBClient.txt | 2 - 5 files changed, 356 insertions(+), 7 deletions(-) create mode 100644 source/connect/connection-options.txt create mode 100644 source/includes/connect/connection-options.php diff --git a/snooty.toml b/snooty.toml index e405fe5f..4db21b99 100644 --- a/snooty.toml +++ b/snooty.toml @@ -29,10 +29,10 @@ toc_landing_pages = [ "/indexes", "/security", "/data-formats", - "/upgrade" + "/upgrade", ] -sharedinclude_root = "https://raw.githubusercontent.com/10gen/docs-shared/main/" +sharedinclude_root = "https://raw.githubusercontent.com/10gen/docs-shared/main/" [substitutions] php-library = "MongoDB PHP Library" @@ -46,3 +46,6 @@ stable-api = "Stable API" library-short = "PHP library" api = "https://www.mongodb.com/docs/php-library/current/reference" php-manual = "https://www.php.net/manual/en" +string-data-type = "``string``" +bool-data-type = "``bool``" +int-data-type = "``int``" diff --git a/source/connect.txt b/source/connect.txt index cc4ff021..30e22002 100644 --- a/source/connect.txt +++ b/source/connect.txt @@ -24,10 +24,8 @@ Connect to MongoDB /connect/client /connect/connection-targets - /connect/tls - -.. TODO: /connect/connection-options + /connect/tls /connect/stable-api Overview diff --git a/source/connect/connection-options.txt b/source/connect/connection-options.txt new file mode 100644 index 00000000..5cbcab35 --- /dev/null +++ b/source/connect/connection-options.txt @@ -0,0 +1,328 @@ +.. _php-connection-options: + +========================== +Specify Connection Options +========================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: connection string, URI, server, Atlas, settings, configure + +Overview +-------- + +This page describes the MongoDB connection and authentication options +available in the {+driver-short+}. + +Set Connection Options +---------------------- + +You can configure your connection by specifying options in the connection URI or by +passing them to the ``MongoDB\Client`` constructor. + +.. _php-connection-uri: + +Using the Connection URI +~~~~~~~~~~~~~~~~~~~~~~~~ + +If you pass a connection URI to the ``MongoDB\Client`` constructor, you can include +connection options in the URI as ``=`` pairs. In the following example, +the connection URI sets the ``tls`` option to ``true`` and the +``tlsCertificateKeyFile`` option to ``/path/to/file.pem``: + +.. literalinclude:: /includes/connect/connection-options.php + :language: php + :copyable: true + :start-after: // start-connection-uri + :end-before: // end-connection-uri + :emphasize-lines: 2,5 + +.. _php-client-object: + +Using a MongoDB\\Client Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can pass connection options to the ``MongoDB\Client`` constructor +instead of including them in your connection URI. + +The following example shows how to use the ``$uriOptions`` parameter of the +``MongoDB\Client`` constructor to set connection options: + +.. literalinclude:: /includes/connect/connection-options.php + :language: php + :copyable: true + :start-after: // start-client-options + :end-before: // end-client-options + :emphasize-lines: 5-8, 11 + +.. note:: + + If you specify an option in both the ``$uriOptions`` parameter and in the connection + URI, the value in ``$uriOptions`` takes precedence. + +Connection URI Options +---------------------- + +The following sections describe the options that you can set for your connection to +MongoDB. Each connection option links to its corresponding +entry in the {+mdb-server+} manual. + +.. important:: Percent-Encoding + + If the value of a connection option contains special characters, you must + :wikipedia:`percent-encode ` the value before including it + in the connection URI. You can use the ``rawurlencode()`` method to encode + these values according to the URI syntax specified in RFC 3986. + + Don't percent-encode connection options when including them in the + ``$uriOptions`` parameter. + + To learn more, see the following resources: + + - `RFC 3986 `__ + - `rawurlencode <{+php-manual+}/rawurlencode>`__ in the PHP manual + +Replica Set Options +~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + + * - Connection Option + - Description + + * - :manual:`directConnection ` + - | **Data Type**: {+bool-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['directConnection' => true];`` + | **Connection URI Example**: ``directConnection=true`` + + * - :manual:`replicaSet ` + - | **Data Type**: {+string-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['replicaSet' => 'replicaSetName'];`` + | **Connection URI Example**: ``replicaSet=replicaSetName`` + +Connection Options +~~~~~~~~~~~~~~~~~~ + +TLS Options +``````````` +To learn about the TLS options available in the {+driver-short+}, see the +:ref:`TLS ` page. + +Timeout Options +``````````````` + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + + * - Connection Option + - Description + + * - :manual:`connectTimeoutMS ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['connectTimeoutMS' => 2000];`` + | **Connection URI Example**: ``connectTimeoutMS=2000`` + + * - :manual:`socketTimeoutMS ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['socketTimeoutMS' => 20000];`` + | **Connection URI Example**: ``socketTimeoutMS=20000`` + +.. _php-compression-options: + +Compression Options +``````````````````` + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + + * - Connection Option + - Description + + * - :manual:`compressors ` + - | **Data Type**: {+string-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['compressors' => 'snappy,zstd,zlib'];`` + | **Connection URI Example**: ``compressors=snappy,zstd,zlib`` + + * - :manual:`zlibCompressionLevel ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['zlibCompressionLevel' => 3];`` + | **Connection URI Example**: ``zlibCompressionLevel=3`` + +Write Concern Options +~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + + * - Connection Option + - Description + + * - :manual:`w ` + - | **Data Type**: {+string-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['w' => 'majority'];`` + | **Connection URI Example**: ``w=majority`` + + * - :manual:`wTimeoutMS ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['wTimeoutMS' => 10000];`` + | **Connection URI Example**: ``wTimeoutMS=10000`` + + * - :manual:`journal ` + - | **Data Type**: {+bool-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['journal' => true];`` + | **Connection URI Example**: ``journal=true`` + +Read Concern Options +~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + + * - Connection Option + - Description + + * - :manual:`readConcernLevel ` + - | **Data Type**: {+string-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['readConcernLevel' => 'majority'];`` + | **Connection URI Example**: ``readConcernLevel=majority`` + +Read Preference Options +~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + :widths: 22 78 + + * - Connection Option + - Description + + * - :manual:`readPreference ` + - | **Data Type**: `MongoDB\\Driver\\ReadPreference `__ + | **MongoDB\\Client Example**: ``$uriOptions = ['readPreference' => 'secondaryPreferred'];`` + | **Connection URI Example**: ``readPreference=secondaryPreferred`` + + * - :manual:`maxStalenessSeconds ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['maxStalenessSeconds' => 30];`` + | **Connection URI Example**: ``maxStalenessSeconds=30`` + + * - :manual:`readPreferenceTags ` + - | **Data Type**: ``array`` + | **MongoDB\\Client Example**: + + .. code-block:: php + + $uriOptions = [ + 'readPreferenceTags' => [ + ['dc' => 'ny', 'rack' => 'r1'], + [], + ], + ]; + + **Connection URI Example**: ``readPreferenceTags=dc:ny,rack:r1&readPreferenceTags=`` + +Authentication Options +~~~~~~~~~~~~~~~~~~~~~~ + +To learn about the authentication options available in the {+driver-short+}, see +:ref:`Authentication Mechanisms. ` + +Server Selection and Discovery Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + :widths: 30 70 + + * - Connection Option + - Description + + * - :manual:`localThresholdMS ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['localThresholdMS' => 20];`` + | **Connection URI Example**: ``localThresholdMS=20`` + + * - :manual:`serverSelectionTimeoutMS ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['serverSelectionTimeoutMS' => 5000];`` + | **Connection URI Example**: ``serverSelectionTimeoutMS=5000`` + + * - :manual:`serverSelectionTryOnce ` + - | **Data Type**: {+bool-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['serverSelectionTryOnce' => false];`` + | **Connection URI Example**: ``serverSelectionTryOnce=false`` + + * - :manual:`heartbeatFrequencyMS ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['heartbeatFrequencyMS' => 30000];`` + | **Connection URI Example**: ``heartbeatFrequencyMS=30000`` + + * - :manual:`socketCheckIntervalMS ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['socketCheckIntervalMS' => 4000];`` + | **Connection URI Example**: ``socketCheckIntervalMS=4000`` + +Miscellaneous Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + + * - Connection Option + - Description + + * - :manual:`appName ` + - | **Data Type**: {+string-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['appName' => 'myApp'];`` + | **Connection URI Example**: ``appName=myApp`` + + * - :manual:`retryReads ` + - | **Data Type**: {+bool-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['retryReads' => false];`` + | **Connection URI Example**: ``retryReads=false`` + + * - :manual:`retryWrites ` + - | **Data Type**: {+bool-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['retryWrites' => false];`` + | **Connection URI Example**: ``retryWrites=false`` + + * - :manual:`loadBalanced ` + - | **Data Type**: {+bool-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['loadBalanced' => true];`` + | **Connection URI Example**: ``loadBalanced=true`` + + * - :manual:`srvMaxHosts ` + - | **Data Type**: {+int-data-type+} + | **MongoDB\\Client Example**: ``$uriOptions = ['srvMaxHosts' => 5];`` + | **Connection URI Example**: ``srvMaxHosts=5`` + +API Documentation +----------------- + +For more information about the ``MongoDB\Client`` class, see the following {+driver-short+} +API documentation: + +- :phpclass:`MongoDB\Client` + +For more information about the ``MongoDB\Driver\ReadPreference`` class, see the following +{+extension-short+} API documentation: + +- `MongoDB\\Driver\\ReadPreference `__ \ No newline at end of file diff --git a/source/includes/connect/connection-options.php b/source/includes/connect/connection-options.php new file mode 100644 index 00000000..f6297065 --- /dev/null +++ b/source/includes/connect/connection-options.php @@ -0,0 +1,22 @@ +// start-connection-uri +// Replace the placeholders with your actual hostname, port, and path to the certificate key file +$uri = "mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/file.pem"; + +// Create a MongoDB client +$client = new MongoDB\Client($uri); +// end-connection-uri + +// start-client-options +// Replace the placeholders with your actual hostname and port +$uri = "mongodb://:/"; + +// Set the connection options +// Replace the placeholder with the actual path to the certificate key file +$uriOptions = [ + 'tls' => true, + 'tlsCertificateKeyFile' => '/path/to/file.pem' +]; + +// Create a MongoDB client with the URI and options +$client = new Client($uri, $uriOptions); +// end-client-options diff --git a/source/reference/class/MongoDBClient.txt b/source/reference/class/MongoDBClient.txt index c7c74f33..25cf7a18 100644 --- a/source/reference/class/MongoDBClient.txt +++ b/source/reference/class/MongoDBClient.txt @@ -1,5 +1,3 @@ -.. _php-api-mongodbclient: - ===================== MongoDB\\Client Class ===================== From 1274cc63185c2a570a631757d02543481b83eaa5 Mon Sep 17 00:00:00 2001 From: Nora Reidy Date: Fri, 27 Sep 2024 16:28:42 -0400 Subject: [PATCH 147/149] DOCSP-43396: Cleanup (#151) * DOCSP-43396: Cleanup * quickstart fix * code fixes * edit * snooty * edit * code output * build log errors * another build fix * add info * upgrade guide to landing * fix * driver mentions * RR feedback * build fix --- snooty.toml | 2 +- source/aggregation.txt | 4 +-- source/connect/client.txt | 2 +- source/connect/connection-options.txt | 2 +- source/connect/connection-targets.txt | 2 +- source/connect/stable-api.txt | 2 +- source/databases-collections.txt | 4 +-- source/get-started/connect-to-mongodb.txt | 29 ++++++++++++++---- source/get-started/next-steps.txt | 9 +++--- source/includes/aggregation.php | 4 +-- source/includes/connect/atlas.php | 7 ++--- source/includes/connect/ca-dir.php | 2 +- source/includes/connect/ca-file-tabs.rst | 4 +-- source/includes/connect/client-cert-tabs.rst | 4 +-- source/includes/connect/crl-file.php | 2 +- source/includes/connect/crl-tabs.rst | 4 +-- source/includes/connect/direct-connection.php | 2 +- .../connect/disable-cert-validation-tabs.rst | 4 +-- .../disable-host-verification-tabs.rst | 4 +-- source/includes/connect/insecure-tls-tabs.rst | 4 +-- source/includes/connect/key-file-password.rst | 4 +-- source/includes/connect/ocsp-tabs.rst | 4 +-- source/includes/connect/replica-set.php | 2 +- source/includes/connect/tls-tabs.rst | 4 +-- source/includes/extracts-bucket-option.yaml | 2 +- .../includes/extracts-collection-option.yaml | 2 +- source/includes/extracts-common-option.yaml | 2 +- source/includes/get-started/quickstart.php | 7 +++-- source/includes/indexes/indexes.php | 2 +- source/includes/read/change-streams.php | 6 ++-- source/includes/read/count.php | 10 +++---- source/includes/read/cursor.php | 4 +-- source/includes/read/distinct.php | 6 ++-- source/includes/read/limit-skip-sort.php | 8 ++--- source/includes/read/project.php | 6 ++-- source/includes/read/retrieve.php | 6 ++-- source/includes/read/specify-queries.php | 16 +++++----- .../usage-examples/read-code-examples.php | 14 ++++----- source/includes/write/delete.php | 2 +- source/includes/write/replace.php | 2 +- source/includes/write/update.php | 2 +- source/index.txt | 16 ++++++---- source/read.txt | 2 +- source/read/change-streams.txt | 8 ++--- source/read/count.txt | 6 ++-- source/read/cursor.txt | 14 +++++---- source/read/distinct.txt | 7 +++-- source/read/project.txt | 6 ++-- source/read/retrieve.txt | 22 ++++++++------ source/read/specify-a-query.txt | 10 +++---- source/read/specify-documents-to-return.txt | 6 ++-- .../method/MongoDBClient-selectCollection.txt | 2 +- .../method/MongoDBCollection-bulkWrite.txt | 2 +- .../method/MongoDBCollection-createIndex.txt | 2 +- .../MongoDBCollection-createIndexes.txt | 2 +- .../method/MongoDBCollection-deleteMany.txt | 2 +- .../method/MongoDBCollection-deleteOne.txt | 2 +- .../method/MongoDBCollection-dropIndex.txt | 2 +- .../method/MongoDBCollection-dropIndexes.txt | 2 +- .../method/MongoDBCollection-getNamespace.txt | 5 ++-- .../method/MongoDBCollection-insertMany.txt | 2 +- .../method/MongoDBCollection-insertOne.txt | 2 +- .../method/MongoDBCollection-listIndexes.txt | 2 +- .../method/MongoDBCollection-replaceOne.txt | 2 +- .../method/MongoDBCollection-updateMany.txt | 2 +- .../method/MongoDBCollection-updateOne.txt | 2 +- .../method/MongoDBCollection-withOptions.txt | 2 +- .../method/MongoDBCollection__construct.txt | 2 +- .../MongoDBDatabase-selectCollection.txt | 2 +- .../MongoDBDatabase-selectGridFSBucket.txt | 2 +- .../method/MongoDBGridFSBucket__construct.txt | 2 +- source/security.txt | 16 ++++++---- source/security/authentication.txt | 10 +++---- source/tutorial.txt | 4 +-- source/tutorial/commands.txt | 2 +- source/upgrade.txt | 30 +++++++++---------- source/write/delete.txt | 6 ++-- source/write/gridfs.txt | 2 +- source/write/insert.txt | 11 ++++--- source/write/replace.txt | 4 +-- source/write/update.txt | 8 ++--- 81 files changed, 239 insertions(+), 202 deletions(-) diff --git a/snooty.toml b/snooty.toml index 4db21b99..aa728e0c 100644 --- a/snooty.toml +++ b/snooty.toml @@ -39,11 +39,11 @@ php-library = "MongoDB PHP Library" [constants] php-library = "MongoDB PHP Library" -driver-short = "PHP library" extension-short = "PHP extension" mdb-server = "MongoDB Server" stable-api = "Stable API" library-short = "PHP library" +driver-short = "{+library-short+}" api = "https://www.mongodb.com/docs/php-library/current/reference" php-manual = "https://www.php.net/manual/en" string-data-type = "``string``" diff --git a/source/aggregation.txt b/source/aggregation.txt index 1a677c95..96e7f63e 100644 --- a/source/aggregation.txt +++ b/source/aggregation.txt @@ -201,5 +201,5 @@ API Documentation To learn more about the methods discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::aggregate() <{+api+}/method/MongoDBCollection-aggregate/>`__ -- `MongoDB\\Collection::explain() <{+api+}/method/MongoDBCollection-explain/>`__ +- :phpmethod:`MongoDB\Collection::aggregate()` +- :phpmethod:`MongoDB\Collection::explain()` diff --git a/source/connect/client.txt b/source/connect/client.txt index 680d293b..bef37b50 100644 --- a/source/connect/client.txt +++ b/source/connect/client.txt @@ -102,4 +102,4 @@ API Documentation To learn more about creating a ``MongoDB\Client`` object in the {+library-short+}, see the following API documentation: -- :ref:`MongoDB\Client ` \ No newline at end of file +- :phpclass:`MongoDB\Client` \ No newline at end of file diff --git a/source/connect/connection-options.txt b/source/connect/connection-options.txt index 5cbcab35..3c19fed2 100644 --- a/source/connect/connection-options.txt +++ b/source/connect/connection-options.txt @@ -89,7 +89,7 @@ entry in the {+mdb-server+} manual. To learn more, see the following resources: - `RFC 3986 `__ - - `rawurlencode <{+php-manual+}/rawurlencode>`__ in the PHP manual + - :php:`rawurlencode ` in the PHP manual Replica Set Options ~~~~~~~~~~~~~~~~~~~ diff --git a/source/connect/connection-targets.txt b/source/connect/connection-targets.txt index ed4441c2..59497bb0 100644 --- a/source/connect/connection-targets.txt +++ b/source/connect/connection-targets.txt @@ -113,4 +113,4 @@ API Documentation To learn more about using the ``MongoDB\Client`` class, see the following API documentation: -- :ref:`MongoDB\Client ` \ No newline at end of file +- :phpclass:`MongoDB\Client` \ No newline at end of file diff --git a/source/connect/stable-api.txt b/source/connect/stable-api.txt index d65bae63..ff2b96cd 100644 --- a/source/connect/stable-api.txt +++ b/source/connect/stable-api.txt @@ -108,7 +108,7 @@ The following code example shows how you can use these parameters when construct API Documentation ----------------- -For more information about the ``MongoDB\Client`` class, see the following {+driver-short+} +For more information about the ``MongoDB\Client`` class, see the following {+library-short+} API documentation: - :phpclass:`MongoDB\Client` diff --git a/source/databases-collections.txt b/source/databases-collections.txt index 0af58b59..43e2786f 100644 --- a/source/databases-collections.txt +++ b/source/databases-collections.txt @@ -66,8 +66,8 @@ the ``test_database`` database: To learn more about ``__get()`` and PHP magic methods, see the following resources: - - :phpmethod:`MongoDB\Client::__get()` in the API documentation - - `Magic Methods <{+php-manual+}/language.oop5.magic.php>`__ in the PHP manual + - :phpmethod:`MongoDB\Client::__get()` in the library API documentation + - :php:`Magic Methods ` in the PHP manual .. _php-db-coll-access-collection: diff --git a/source/get-started/connect-to-mongodb.txt b/source/get-started/connect-to-mongodb.txt index 7492fe25..a205c8c5 100644 --- a/source/get-started/connect-to-mongodb.txt +++ b/source/get-started/connect-to-mongodb.txt @@ -29,9 +29,26 @@ the Atlas sample datasets. .. step:: Assign the connection string - Replace the ```` placeholder with the - connection string that you copied from the :ref:`php-connection-string` - step of this guide. + Assign the ``MONGODB_URI`` environment variable to the connection string that you copied + from the :ref:`php-connection-string` step of this guide. You can assign this + variable by running a shell command or creating a ``.env`` file in your application, + as show in the following tabs: + + .. tabs:: + + .. tab:: Shell Command + :tabid: shell + + .. code-block:: sh + + export MONGODB_URI= + + .. tab:: .env File + :tabid: dotenv + + .. code-block:: none + + MONGODB_URI= .. step:: Run your PHP application @@ -58,9 +75,9 @@ the Atlas sample datasets. ... } - If you encounter an error or see no output, ensure that you specified the - proper connection string in the ``quickstart.php`` file and that you loaded the - sample data. + If you encounter an error or see no output, ensure that you assigned the + proper connection string to the ``MONGODB_URI`` environment variable and + that you loaded the sample data. After you complete these steps, you have a PHP application that connects to your MongoDB deployment, runs a query on the sample diff --git a/source/get-started/next-steps.txt b/source/get-started/next-steps.txt index 3be97ed2..2fe8d5d5 100644 --- a/source/get-started/next-steps.txt +++ b/source/get-started/next-steps.txt @@ -17,7 +17,8 @@ In this tutorial, you created a PHP application that connects to a MongoDB deployment hosted on MongoDB Atlas and retrieves a document that matches a query. -.. TODO: - Learn more about the {+php-library+} from the following resources: - - Learn how to perform read operations in the :ref:`` section. - - Learn how to perform write operations in the :ref:`` section. \ No newline at end of file + +Learn more about the {+php-library+} from the following resources: + +- Learn how to perform read operations in the :ref:`` section. +- Learn how to perform write operations in the :ref:`` section. \ No newline at end of file diff --git a/source/includes/aggregation.php b/source/includes/aggregation.php index e2cfa914..e8b1a7f9 100644 --- a/source/includes/aggregation.php +++ b/source/includes/aggregation.php @@ -17,7 +17,7 @@ $cursor = $collection->aggregate($pipeline); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-match-group @@ -35,6 +35,6 @@ ); $result = $collection->explain($aggregate); -echo json_encode($result) , PHP_EOL; +echo json_encode($result), PHP_EOL; // end-explain diff --git a/source/includes/connect/atlas.php b/source/includes/connect/atlas.php index 29d219d5..43bb4ab2 100644 --- a/source/includes/connect/atlas.php +++ b/source/includes/connect/atlas.php @@ -1,7 +1,7 @@ "; +$uri = ''; // Create a MongoDB client with server API options $client = new MongoDB\Client($uri, [], [ @@ -13,7 +13,6 @@ $command = new MongoDB\Driver\Command(['ping' => 1]); $result = $admin->command($command)->toArray(); -echo json_encode($result), "\n"; -echo "Pinged your deployment. You successfully connected to MongoDB!\n"; +echo json_encode($result), PHP_EOL; +echo 'Pinged your deployment. You successfully connected to MongoDB!\n'; -?> diff --git a/source/includes/connect/ca-dir.php b/source/includes/connect/ca-dir.php index 3618529b..03e88108 100644 --- a/source/includes/connect/ca-dir.php +++ b/source/includes/connect/ca-dir.php @@ -1,4 +1,4 @@ -$uri = "mongodb://:"; +$uri = 'mongodb://:'; $uriOptions = [ 'tls' => true, diff --git a/source/includes/connect/ca-file-tabs.rst b/source/includes/connect/ca-file-tabs.rst index b0b85bc8..57bfd343 100644 --- a/source/includes/connect/ca-file-tabs.rst +++ b/source/includes/connect/ca-file-tabs.rst @@ -5,7 +5,7 @@ .. code-block:: php - $uri = "mongodb://:"; + $uri = 'mongodb://:'; $options = [ 'tls' => true, @@ -19,5 +19,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true&tlsCAFile=/path/to/ca.pem"; + $uri = 'mongodb://:/?tls=true&tlsCAFile=/path/to/ca.pem'; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/client-cert-tabs.rst b/source/includes/connect/client-cert-tabs.rst index 961fc987..a93a9185 100644 --- a/source/includes/connect/client-cert-tabs.rst +++ b/source/includes/connect/client-cert-tabs.rst @@ -5,7 +5,7 @@ .. code-block:: php - $uri = "mongodb://:"; + $uri = 'mongodb://:'; $options = [ 'tls' => true, @@ -19,5 +19,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/client.pem"; + $uri = 'mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/client.pem'; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/crl-file.php b/source/includes/connect/crl-file.php index 1a37b5e2..8904c0e4 100644 --- a/source/includes/connect/crl-file.php +++ b/source/includes/connect/crl-file.php @@ -1,4 +1,4 @@ -$uri = "mongodb://:"; +$uri = 'mongodb://:'; $uriOptions = [ 'tls' => true, diff --git a/source/includes/connect/crl-tabs.rst b/source/includes/connect/crl-tabs.rst index f0a63f9d..3784ce06 100644 --- a/source/includes/connect/crl-tabs.rst +++ b/source/includes/connect/crl-tabs.rst @@ -5,7 +5,7 @@ .. code-block:: php - $uri = "mongodb://:"; + $uri = 'mongodb://:'; $options = [ 'tls' => true, @@ -19,5 +19,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true&tlsCRLFile=/path/to/crl.pem"; + $uri = 'mongodb://:/?tls=true&tlsCRLFile=/path/to/crl.pem'; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/direct-connection.php b/source/includes/connect/direct-connection.php index fd896b3c..665bc3ae 100644 --- a/source/includes/connect/direct-connection.php +++ b/source/includes/connect/direct-connection.php @@ -1,7 +1,7 @@ :/?directConnection=true"; +$uri = 'mongodb://:/?directConnection=true'; // Create a MongoDB client $client = new MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/disable-cert-validation-tabs.rst b/source/includes/connect/disable-cert-validation-tabs.rst index bcdc0e76..60e77093 100644 --- a/source/includes/connect/disable-cert-validation-tabs.rst +++ b/source/includes/connect/disable-cert-validation-tabs.rst @@ -5,7 +5,7 @@ .. code-block:: php - $uri = "mongodb://:"; + $uri = 'mongodb://:'; $options = [ 'tls' => true, @@ -19,5 +19,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true&tlsAllowInvalidCertificates=true"; + $uri = 'mongodb://:/?tls=true&tlsAllowInvalidCertificates=true'; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/disable-host-verification-tabs.rst b/source/includes/connect/disable-host-verification-tabs.rst index db4b8d1b..96cc4cfc 100644 --- a/source/includes/connect/disable-host-verification-tabs.rst +++ b/source/includes/connect/disable-host-verification-tabs.rst @@ -5,7 +5,7 @@ .. code-block:: php - $uri = "mongodb://:"; + $uri = 'mongodb://:'; $options = [ 'tls' => true, @@ -19,5 +19,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true&tlsAllowInvalidHostnames=true"; + $uri = 'mongodb://:/?tls=true&tlsAllowInvalidHostnames=true'; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/insecure-tls-tabs.rst b/source/includes/connect/insecure-tls-tabs.rst index 97600fbf..e04e56ea 100644 --- a/source/includes/connect/insecure-tls-tabs.rst +++ b/source/includes/connect/insecure-tls-tabs.rst @@ -5,7 +5,7 @@ .. code-block:: php - $uri = "mongodb://:"; + $uri = 'mongodb://:'; $options = [ 'tls' => true, @@ -19,5 +19,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true&tlsInsecure=true"; + $uri = 'mongodb://:/?tls=true&tlsInsecure=true'; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/key-file-password.rst b/source/includes/connect/key-file-password.rst index 2cb710c9..a6b2f8ea 100644 --- a/source/includes/connect/key-file-password.rst +++ b/source/includes/connect/key-file-password.rst @@ -5,7 +5,7 @@ .. code-block:: php - $uri = "mongodb://:"; + $uri = 'mongodb://:'; $options = [ 'tls' => true, @@ -20,5 +20,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/client.pem&tlsCertificateKeyFilePassword="; + $uri = 'mongodb://:/?tls=true&tlsCertificateKeyFile=/path/to/client.pem&tlsCertificateKeyFilePassword='; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/ocsp-tabs.rst b/source/includes/connect/ocsp-tabs.rst index 1e393689..467fed14 100644 --- a/source/includes/connect/ocsp-tabs.rst +++ b/source/includes/connect/ocsp-tabs.rst @@ -5,7 +5,7 @@ .. code-block:: php - $uri = "mongodb://:"; + $uri = 'mongodb://:'; $options = [ 'tls' => true, @@ -19,5 +19,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true&tlsDisableOCSPEndpointCheck=true"; + $uri = 'mongodb://:/?tls=true&tlsDisableOCSPEndpointCheck=true'; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/connect/replica-set.php b/source/includes/connect/replica-set.php index 6086d425..cd8840fb 100644 --- a/source/includes/connect/replica-set.php +++ b/source/includes/connect/replica-set.php @@ -1,6 +1,6 @@ :"; + $uri = 'mongodb://:'; $options = [ 'tls' => true @@ -18,5 +18,5 @@ .. code-block:: php - $uri = "mongodb://:/?tls=true"; + $uri = 'mongodb://:/?tls=true'; $client = MongoDB\Client($uri); \ No newline at end of file diff --git a/source/includes/extracts-bucket-option.yaml b/source/includes/extracts-bucket-option.yaml index a3eb915f..1ca8a553 100644 --- a/source/includes/extracts-bucket-option.yaml +++ b/source/includes/extracts-bucket-option.yaml @@ -1,6 +1,6 @@ ref: bucket-option-codec content: | - The :doc:`codec ` to use for encoding or decoding documents. + The :doc:`codec ` to use for encoding or decoding documents. This option is mutually exclusive with the ``typeMap`` option. Defaults to the bucket's codec. Inheritance for a default ``codec`` option diff --git a/source/includes/extracts-collection-option.yaml b/source/includes/extracts-collection-option.yaml index ecc82a42..c293dc62 100644 --- a/source/includes/extracts-collection-option.yaml +++ b/source/includes/extracts-collection-option.yaml @@ -1,6 +1,6 @@ ref: collection-option-codec content: | - The :doc:`codec ` to use for encoding or decoding documents. + The :doc:`codec ` to use for encoding or decoding documents. This option is mutually exclusive with the ``typeMap`` option. Defaults to the collection's codec. Inheritance for a default ``codec`` option diff --git a/source/includes/extracts-common-option.yaml b/source/includes/extracts-common-option.yaml index 39cab355..68702d6e 100644 --- a/source/includes/extracts-common-option.yaml +++ b/source/includes/extracts-common-option.yaml @@ -1,6 +1,6 @@ ref: common-option-codec content: | - The :doc:`codec ` to use for encoding or decoding documents. + The :doc:`codec ` to use for encoding or decoding documents. This option is mutually exclusive with the ``typeMap`` option. --- ref: common-option-collation diff --git a/source/includes/get-started/quickstart.php b/source/includes/get-started/quickstart.php index d62dd83e..58237258 100644 --- a/source/includes/get-started/quickstart.php +++ b/source/includes/get-started/quickstart.php @@ -4,7 +4,10 @@ use MongoDB\Client; -$client = new Client(''); +$uri = getenv('MONGODB_URI') ?: throw new RuntimeException( + 'Set the MONGODB_URI environment variable to your Atlas URI' +); +$client = new MongoDB\Client($uri); $collection = $client->sample_mflix->movies; $filter = ['title' => 'The Shawshank Redemption']; @@ -13,5 +16,5 @@ if ($result) { echo json_encode($result, JSON_PRETTY_PRINT); } else { - echo "Document not found"; + echo 'Document not found'; } diff --git a/source/includes/indexes/indexes.php b/source/includes/indexes/indexes.php index 235e3ee5..3b293fb1 100644 --- a/source/includes/indexes/indexes.php +++ b/source/includes/indexes/indexes.php @@ -42,7 +42,7 @@ ['title' => ['$regex' => 'Sunrise'], 'year' => ['$gte' => 1990]] ); -echo json_encode($document) , PHP_EOL; +echo json_encode($document), PHP_EOL; // end-compound-query // start-multikey diff --git a/source/includes/read/change-streams.php b/source/includes/read/change-streams.php index 5b51d1a6..b00ced02 100644 --- a/source/includes/read/change-streams.php +++ b/source/includes/read/change-streams.php @@ -24,7 +24,7 @@ function toJSON(object $document): string continue; } $event = $changeStream->current(); - echo toJSON($event) . PHP_EOL; + echo toJSON($event), PHP_EOL; if ($event['operationType'] === 'invalidate') { break; @@ -50,7 +50,7 @@ function toJSON(object $document): string continue; } $event = $changeStream->current(); - echo toJSON($event) . PHP_EOL; + echo toJSON($event), PHP_EOL; if ($event['operationType'] === 'invalidate') { break; @@ -68,7 +68,7 @@ function toJSON(object $document): string continue; } $event = $changeStream->current(); - echo toJSON($event) . PHP_EOL; + echo toJSON($event), PHP_EOL; if ($event['operationType'] === 'invalidate') { break; diff --git a/source/includes/read/count.php b/source/includes/read/count.php index 3167cb90..e76bbedf 100644 --- a/source/includes/read/count.php +++ b/source/includes/read/count.php @@ -13,13 +13,13 @@ // Counts all documents in the collection // start-count-all $result = $collection->countDocuments([]); -echo "Number of documents: " . $result; +echo 'Number of documents: ', $result; // end-count-all // Counts documents that have a "founded_year" value of 2010 // start-count-accurate $result = $collection->countDocuments(['founded_year' => 2010]); -echo "Number of companies founded in 2010: " . $result; +echo 'Number of companies founded in 2010: ', $result; // end-count-accurate // Counts a maximum of 100 documents that have a "number_of_employees" value of 50 @@ -28,17 +28,17 @@ ['number_of_employees' => 50], ['limit' => 100] ); -echo "Number of companies with 50 employees: " . $result; +echo 'Number of companies with 50 employees: ', $result; // end-modify-accurate // Estimates the number of documents in the collection // start-count-estimate $result = $collection->estimatedDocumentCount(); -echo "Estimated number of documents: " . $result; +echo 'Estimated number of documents: ', $result; // end-count-estimate // Estimates the number of documents in the collection and sets a time limit on the operation // start-modify-estimate $result = $collection->estimatedDocumentCount(['maxTimeMS' => 1000]); -echo "Estimated number of documents: " . $result; +echo 'Estimated number of documents: ', $result; // end-modify-estimate diff --git a/source/includes/read/cursor.php b/source/includes/read/cursor.php index 7747a52c..7ea0648a 100644 --- a/source/includes/read/cursor.php +++ b/source/includes/read/cursor.php @@ -12,7 +12,7 @@ // start-cursor-iterate $cursor = $collection->find(['name' => 'Dunkin\' Donuts']); foreach ($cursor as $doc) { - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-cursor-iterate @@ -56,7 +56,7 @@ while ($docs_found < 3) { if ($cursor->valid()) { $doc = $cursor->current(); - echo json_encode($doc) . PHP_EOL; + echo json_encode($doc), PHP_EOL; $docs_found++; } $cursor->next(); diff --git a/source/includes/read/distinct.php b/source/includes/read/distinct.php index 5ac02f97..92745a3c 100644 --- a/source/includes/read/distinct.php +++ b/source/includes/read/distinct.php @@ -14,7 +14,7 @@ // start-distinct $results = $collection->distinct('borough', []); foreach ($results as $value) { - echo json_encode($value) . PHP_EOL; + echo json_encode($value), PHP_EOL; } // end-distinct @@ -22,7 +22,7 @@ // start-distinct-with-query $results = $collection->distinct('borough', ['cuisine' => 'Italian']); foreach ($results as $value) { - echo json_encode($value) . PHP_EOL; + echo json_encode($value), PHP_EOL; } // end-distinct-with-query @@ -34,7 +34,7 @@ $results = $collection->distinct('name', $query, $options); foreach ($results as $value) { - echo json_encode($value) . PHP_EOL; + echo json_encode($value), PHP_EOL; } // end-distinct-with-comment diff --git a/source/includes/read/limit-skip-sort.php b/source/includes/read/limit-skip-sort.php index 8beec933..433a6e6b 100644 --- a/source/includes/read/limit-skip-sort.php +++ b/source/includes/read/limit-skip-sort.php @@ -17,7 +17,7 @@ ); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-limit @@ -29,7 +29,7 @@ ); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-sort @@ -41,7 +41,7 @@ ); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-skip @@ -56,7 +56,7 @@ $cursor = $collection->find(['cuisine' => 'Italian'], $options); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-limit-sort-skip diff --git a/source/includes/read/project.php b/source/includes/read/project.php index 3f63d93b..c601402f 100644 --- a/source/includes/read/project.php +++ b/source/includes/read/project.php @@ -21,7 +21,7 @@ $cursor = $collection->find(['name' => 'Emerald Pub'], $options); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-project-include @@ -39,7 +39,7 @@ $cursor = $collection->find(['name' => 'Emerald Pub'], $options); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-project-include-without-id @@ -54,6 +54,6 @@ $cursor = $collection->find(['name' => 'Emerald Pub'], $options); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-project-exclude diff --git a/source/includes/read/retrieve.php b/source/includes/read/retrieve.php index ed086984..27765c96 100644 --- a/source/includes/read/retrieve.php +++ b/source/includes/read/retrieve.php @@ -11,7 +11,7 @@ // Finds one document with a "name" value of "LinkedIn" // start-find-one $document = $collection->findOne(['name' => 'LinkedIn']); -echo json_encode($document) , "\n"; +echo json_encode($document), PHP_EOL; // end-find-one // Finds documents with a "founded_year" value of 1970 @@ -22,7 +22,7 @@ // Prints documents with a "founded_year" value of 1970 // start-cursor foreach ($results as $doc) { - echo json_encode($doc) , "\n"; + echo json_encode($doc), PHP_EOL; } // end-cursor @@ -34,6 +34,6 @@ ); foreach ($results as $doc) { - echo json_encode($doc) , "\n"; + echo json_encode($doc), PHP_EOL; } // end-modify diff --git a/source/includes/read/specify-queries.php b/source/includes/read/specify-queries.php index df7e1c11..27ce4ebd 100644 --- a/source/includes/read/specify-queries.php +++ b/source/includes/read/specify-queries.php @@ -5,7 +5,7 @@ use MongoDB\Client; // start-setup -$uri = ""; +$uri = ''; $client = new Client($uri); $collection = $client->db->fruits; @@ -50,7 +50,7 @@ // start-find-exact $cursor = $collection->find(['color' => 'yellow']); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-find-exact @@ -58,7 +58,7 @@ // start-find-all $cursor = $collection->find([]); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-find-all @@ -66,7 +66,7 @@ // start-find-comparison $cursor = $collection->find(['rating' => ['$gt' => 2]]); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-find-comparison @@ -79,7 +79,7 @@ ] ]); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-find-logical @@ -87,7 +87,7 @@ // start-find-array $cursor = $collection->find(['type' => ['$size' => 2]]); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-find-array @@ -95,7 +95,7 @@ // start-find-element $cursor = $collection->find(['color' => ['$exists' => true]]); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-find-element @@ -103,6 +103,6 @@ // start-find-evaluation $cursor = $collection->find(['name' => ['$regex' => 'p{2,}']]); foreach ($cursor as $doc) { - echo json_encode($doc) , PHP_EOL; + echo json_encode($doc), PHP_EOL; } // end-find-evaluation diff --git a/source/includes/usage-examples/read-code-examples.php b/source/includes/usage-examples/read-code-examples.php index e6203cdf..d0db63b9 100644 --- a/source/includes/usage-examples/read-code-examples.php +++ b/source/includes/usage-examples/read-code-examples.php @@ -12,40 +12,40 @@ // Find One // start-find-one $document = $collection->findOne(['year' => 1994]); -echo json_encode($document) , "\n"; +echo json_encode($document), PHP_EOL; // end-find-one // Find Multiple // start-find-multiple $resultsMultiple = $collection->find(['year' => 1970]); foreach ($resultsMultiple as $doc) { - echo json_encode($doc) , "\n"; + echo json_encode($doc), PHP_EOL; } // end-find-multiple // Count Document // start-count $result = $collection->countDocuments([]); -echo "Number of documents: " . $result; +echo 'Number of documents: ', $result; // end-count // Count Specific Documents // start-count-specific $result = $collection->countDocuments(['year' => 2010]); -echo "Number of companies founded in 2010: " . $result; +echo 'Number of companies founded in 2010: ', $result; // end-count-specific // Estimated Count // start-count-estimate $result = $collection->estimatedDocumentCount(); -echo "Estimated number of documents: " . $result; +echo 'Estimated number of documents: ', $result; // end-count-estimate // Distinct Values // start-distinct $results = $collection->distinct('year'); foreach ($results as $value) { - echo json_encode($value) . PHP_EOL; + echo json_encode($value), PHP_EOL; } // end-distinct @@ -58,7 +58,7 @@ continue; } $event = $changeStream->current(); - echo toJSON($event) . PHP_EOL; + echo toJSON($event), PHP_EOL; if ($event['operationType'] === 'invalidate') { break; diff --git a/source/includes/write/delete.php b/source/includes/write/delete.php index 50a5f910..bab197a6 100644 --- a/source/includes/write/delete.php +++ b/source/includes/write/delete.php @@ -29,6 +29,6 @@ // Deletes and prints the number of documents that have a "cuisine" value of "Greek" // start-delete-count $result = $collection->deleteMany(['cuisine' => 'Greek']); -echo 'Deleted documents: ' , $result->getDeletedCount() , PHP_EOL; +echo 'Deleted documents: ', $result->getDeletedCount(), PHP_EOL; // end-delete-count diff --git a/source/includes/write/replace.php b/source/includes/write/replace.php index 05a787c3..7c14c806 100644 --- a/source/includes/write/replace.php +++ b/source/includes/write/replace.php @@ -20,7 +20,7 @@ ]; $result = $collection->replaceOne(['name' => 'Pizza Town'], $replace_document); -echo 'Modified documents: ' . $result->getModifiedCount(); +echo 'Modified documents: ', $result->getModifiedCount(); // end-replace-one // start-replace-options diff --git a/source/includes/write/update.php b/source/includes/write/update.php index 2aee12b7..cd43f60c 100644 --- a/source/includes/write/update.php +++ b/source/includes/write/update.php @@ -40,6 +40,6 @@ ['name' => 'Dunkin\' Donuts'], ['$set' => ['name' => 'Dunkin\'']] ); -echo 'Modified documents: ' . $result->getModifiedCount(); +echo 'Modified documents: ', $result->getModifiedCount(); // end-update-result diff --git a/source/index.txt b/source/index.txt index f2cb82be..5627d911 100644 --- a/source/index.txt +++ b/source/index.txt @@ -70,6 +70,12 @@ Write Data to MongoDB Learn how you can write data to MongoDB in the :ref:`php-write` section. +Specify How CRUD Operations Run on Replica Sets +----------------------------------------------- + +Learn how to configure settings for read and write operations on replica +sets in the :ref:`php-read-write-pref` section. + Run a Database Command ---------------------- @@ -117,12 +123,12 @@ What's New Learn about new features and changes in each version in the :ref:`` section. -.. TODO: - Upgrade {+library-short+} Versions - ---------------------------------- + +Upgrade Library Versions +------------------------ - .. Learn what changes you must make to your application to upgrade driver versions - .. in the :ref:`php-upgrade` section. +Learn what changes you must make to your application to upgrade library and +extension versions in the :ref:`php-upgrade` section. FAQ --- diff --git a/source/read.txt b/source/read.txt index edc62a13..b3c0b89d 100644 --- a/source/read.txt +++ b/source/read.txt @@ -35,7 +35,7 @@ Overview -------- On this page, you can see copyable code examples that show common -{+driver-short+} methods for retrieving documents. +{+library-short+} methods for retrieving documents. .. tip:: diff --git a/source/read/change-streams.txt b/source/read/change-streams.txt index 757c1e7b..37bc6340 100644 --- a/source/read/change-streams.txt +++ b/source/read/change-streams.txt @@ -262,7 +262,7 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Client::watch() <{+api+}/method/MongoDBClient-watch/>`__ -- `MongoDB\\Database::watch() <{+api+}/method/MongoDBDatabase-watch/>`__ -- `MongoDB\\Collection::watch() <{+api+}/method/MongoDBCollection-watch/>`__ -- `MongoDB\\Collection::updateOne() <{+api+}/method/MongoDBCollection-updateOne/>`__ \ No newline at end of file +- :phpmethod:`MongoDB\Client::watch()` +- :phpmethod:`MongoDB\Database::watch()` +- :phpmethod:`MongoDB\Collection::watch()` +- :phpmethod:`MongoDB\Collection::updateOne()` \ No newline at end of file diff --git a/source/read/count.txt b/source/read/count.txt index 9036e8c5..19765deb 100644 --- a/source/read/count.txt +++ b/source/read/count.txt @@ -36,7 +36,7 @@ Sample Data The examples in this guide use the ``companies`` collection in the ``sample_training`` database from the :atlas:`Atlas sample datasets `. To access this collection from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster -and assign the following value to your ``collection`` variable: +and assign the following value to your ``$collection`` variable: .. literalinclude:: /includes/read/count.php :language: php @@ -252,5 +252,5 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::countDocuments() <{+api+}/method/MongoDBCollection-countDocuments/>`__ -- `MongoDB\\Collection::estimatedDocumentCount() <{+api+}/method/MongoDBCollection-estimatedDocumentCount/>`__ \ No newline at end of file +- :phpmethod:`MongoDB\Collection::countDocuments()` +- :phpmethod:`MongoDB\Collection::estimatedDocumentCount()` \ No newline at end of file diff --git a/source/read/cursor.txt b/source/read/cursor.txt index 1fb36fb6..2ecee070 100644 --- a/source/read/cursor.txt +++ b/source/read/cursor.txt @@ -127,6 +127,8 @@ in an array: :start-after: start-cursor-array :end-before: end-cursor-array +.. _php-tailable-cursor: + Tailable Cursors ---------------- @@ -174,15 +176,15 @@ Additional Information To learn more about read operations, see the :ref:`php-retrieve` guide. -To learn more about cursors, see the following pages in the PHP manual: +To learn more about cursors, see the following pages in the extension API documentation: -- `MongoDB\\Driver\\Cursor <{+php-manual+}/class.mongodb-driver-cursor.php>`__ -- `MongoDB\\Driver\\Cursor::current() <{+php-manual+}/mongodb-driver-cursor.current.php>`__ -- `MongoDB\\Driver\\Cursor::toArray() <{+php-manual+}/mongodb-driver-cursor.toarray.php>`__ -- `iterator_to_array() <{+php-manual+}/function.iterator-to-array.php>`__ +- :php:`MongoDB\Driver\Cursor ` +- :php:`MongoDB\Driver\Cursor::current() ` +- :php:`MongoDB\Driver\Cursor::toArray() ` +- :php:`iterator_to_array() ` API Documentation ~~~~~~~~~~~~~~~~~ To learn more about the ``find()`` method, see the API documentation for -`MongoDB\\Collection::find() <{+api+}/method/MongoDBCollection-find/>`__. \ No newline at end of file +:phpmethod:`MongoDB\Collection::find()`. \ No newline at end of file diff --git a/source/read/distinct.txt b/source/read/distinct.txt index 18b9de2f..31d88bd5 100644 --- a/source/read/distinct.txt +++ b/source/read/distinct.txt @@ -35,7 +35,7 @@ Sample Data The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` database from the :atlas:`Atlas sample datasets `. To access this collection from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster -and assign the following value to your ``collection`` variable: +and assign the following value to your ``$collection`` variable: .. literalinclude:: /includes/read/distinct.php :language: php @@ -68,6 +68,7 @@ the ``restaurants`` collection: :dedent: .. output:: + :visible: false "Bronx" "Manhattan" @@ -167,5 +168,5 @@ in an options array to add a comment to the operation: API Documentation ----------------- -To learn more about the ``MongoDB\Collection::distinct()`` method, see the -`distinct() API documentation <{+api+}/method/MongoDBCollection-distinct/>`__. \ No newline at end of file +To learn more about the ``distinct()`` method, see +:phpmethod:`MongoDB\Collection::distinct()` in the API documentation. \ No newline at end of file diff --git a/source/read/project.txt b/source/read/project.txt index 7b568185..9c55b8f7 100644 --- a/source/read/project.txt +++ b/source/read/project.txt @@ -30,7 +30,7 @@ Sample Data The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` database from the :atlas:`Atlas sample datasets `. To access this collection from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster -and assign the following value to your ``collection`` variable: +and assign the following value to your ``$collection`` variable: .. literalinclude:: /includes/read/project.php :language: php @@ -168,5 +168,5 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ -- `MongoDB\\Collection::find() <{+api+}/method/MongoDBCollection-find/>`__ \ No newline at end of file +- :phpmethod:`MongoDB\Collection::findOne()` +- :phpmethod:`MongoDB\Collection::find()` \ No newline at end of file diff --git a/source/read/retrieve.txt b/source/read/retrieve.txt index 283c29aa..58a032f5 100644 --- a/source/read/retrieve.txt +++ b/source/read/retrieve.txt @@ -31,7 +31,7 @@ Sample Data The examples in this guide use the ``companies`` collection in the ``sample_training`` database from the :atlas:`Atlas sample datasets `. To access this collection from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster -and assign the following value to your ``collection`` variable: +and assign the following value to your ``$collection`` variable: .. literalinclude:: /includes/read/retrieve.php :language: php @@ -52,7 +52,9 @@ The {+php-library+} includes two methods for retrieving documents from a collect take a **query filter** and return one or more matching documents. A query filter specifies the search criteria that the driver uses to retrieve documents in your query. -To learn more about query filters, see :ref:`php-specify-query`. +.. tip:: + + To learn more about query filters, see the :ref:`php-specify-query` guide. .. _php-retrieve-find-one: @@ -88,6 +90,7 @@ the ``name`` field has the value ``'LinkedIn'``: :dedent: .. output:: + :visible: false {"_id":{"$oid":"..."},"name":"LinkedIn","permalink":"linkedin","crunchbase_url": "http:\/\/www.crunchbase.com\/company\/linkedin","homepage_url":"http:\/\/linkedin.com", @@ -136,6 +139,7 @@ the following example: :dedent: .. output:: + :visible: false {"_id":{"$oid":"..."},"name":"Mitsubishi Motors","permalink":"mitsubishi-motors", "crunchbase_url":"http:\/\/www.crunchbase.com\/company\/mitsubishi-motors", @@ -229,16 +233,16 @@ For a full list of options, see the API documentation for the Additional Information ---------------------- -.. TODO: - To learn more about query filters, see :ref:`php-specify-query`. - For runnable code examples of retrieving documents with the {+php-library+}, - see :ref:`php-read`. +To learn more about query filters, see the :ref:`php-specify-query` guide. + +To view code examples of retrieving documents with the {+php-library+}, +see :ref:`php-read`. API Documentation ~~~~~~~~~~~~~~~~~ -To learn more about any of the methods or types discussed in this +To learn more about any of the methods discussed in this guide, see the following API documentation: -- `findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ -- `find() <{+api+}/method/MongoDBCollection-find/>`__ \ No newline at end of file +- :phpmethod:`MongoDB\Collection::findOne()` +- :phpmethod:`MongoDB\Collection::find()` \ No newline at end of file diff --git a/source/read/specify-a-query.txt b/source/read/specify-a-query.txt index 9e38c2f6..53e00809 100644 --- a/source/read/specify-a-query.txt +++ b/source/read/specify-a-query.txt @@ -251,9 +251,9 @@ Additional Information To learn more about querying documents, see the :manual:`Query Documents ` guide in the {+mdb-server+} manual. -.. TODO: - To learn more about retrieving documents with the {+php-library+}, see the - :ref:`php-retrieve` guide. + +To learn more about retrieving documents with the {+php-library+}, see the +:ref:`php-retrieve` guide. API Documentation ~~~~~~~~~~~~~~~~~ @@ -261,5 +261,5 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::find() <{+api+}/method/MongoDBCollection-find/>`__ -- `MongoDB\\Collection::insertMany() <{+api+}/method/MongoDBCollection-insertMany/>`__ \ No newline at end of file +- :phpmethod:`MongoDB\Collection::insertMany()` +- :phpmethod:`MongoDB\Collection::find()` \ No newline at end of file diff --git a/source/read/specify-documents-to-return.txt b/source/read/specify-documents-to-return.txt index 4497569f..ef3207c2 100644 --- a/source/read/specify-documents-to-return.txt +++ b/source/read/specify-documents-to-return.txt @@ -38,7 +38,7 @@ Sample Data The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` database from the :atlas:`Atlas sample datasets `. To access this collection from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster -and assign the following value to your ``collection`` variable: +and assign the following value to your ``$collection`` variable: .. literalinclude:: /includes/read/limit-skip-sort.php :language: php @@ -271,5 +271,5 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::findOne() <{+api+}/method/MongoDBCollection-findOne/>`__ -- `MongoDB\\Collection::find() <{+api+}/method/MongoDBCollection-find/>`__ +- :phpmethod:`MongoDB\Collection::findOne()` +- :phpmethod:`MongoDB\Collection::find()` diff --git a/source/reference/method/MongoDBClient-selectCollection.txt b/source/reference/method/MongoDBClient-selectCollection.txt index c1984500..b45b83dd 100644 --- a/source/reference/method/MongoDBClient-selectCollection.txt +++ b/source/reference/method/MongoDBClient-selectCollection.txt @@ -47,7 +47,7 @@ Parameters * - codec - MongoDB\\Codec\\DocumentCodec - - The default :doc:`codec ` to use for collection + - The default :doc:`codec ` to use for collection operations. .. versionadded:: 1.17 diff --git a/source/reference/method/MongoDBCollection-bulkWrite.txt b/source/reference/method/MongoDBCollection-bulkWrite.txt index ad31f062..1f273e76 100644 --- a/source/reference/method/MongoDBCollection-bulkWrite.txt +++ b/source/reference/method/MongoDBCollection-bulkWrite.txt @@ -147,4 +147,4 @@ See Also - :phpmethod:`MongoDB\Collection::replaceOne()` - :phpmethod:`MongoDB\Collection::updateMany()` - :phpmethod:`MongoDB\Collection::updateOne()` -- :doc:`/tutorial/crud` +- :ref:`php-write` diff --git a/source/reference/method/MongoDBCollection-createIndex.txt b/source/reference/method/MongoDBCollection-createIndex.txt index 6a74a5bd..108d12f6 100644 --- a/source/reference/method/MongoDBCollection-createIndex.txt +++ b/source/reference/method/MongoDBCollection-createIndex.txt @@ -201,7 +201,7 @@ See Also -------- - :phpmethod:`MongoDB\Collection::createIndexes()` -- :doc:`/tutorial/indexes` +- :ref:`php-indexes` - :manual:`createIndexes ` command reference in the MongoDB manual - :manual:`Index ` documentation in the MongoDB Manual diff --git a/source/reference/method/MongoDBCollection-createIndexes.txt b/source/reference/method/MongoDBCollection-createIndexes.txt index 85318b2d..4357a9f7 100644 --- a/source/reference/method/MongoDBCollection-createIndexes.txt +++ b/source/reference/method/MongoDBCollection-createIndexes.txt @@ -167,7 +167,7 @@ See Also -------- - :phpmethod:`MongoDB\Collection::createIndex()` -- :doc:`/tutorial/indexes` +- :ref:`php-indexes` - :manual:`createIndexes ` command reference in the MongoDB manual - :manual:`Index ` documentation in the MongoDB Manual diff --git a/source/reference/method/MongoDBCollection-deleteMany.txt b/source/reference/method/MongoDBCollection-deleteMany.txt index b82b1c6b..d30a169d 100644 --- a/source/reference/method/MongoDBCollection-deleteMany.txt +++ b/source/reference/method/MongoDBCollection-deleteMany.txt @@ -129,6 +129,6 @@ See Also - :phpmethod:`MongoDB\Collection::deleteOne()` - :phpmethod:`MongoDB\Collection::bulkWrite()` -- :doc:`/tutorial/crud` +- :ref:`php-write-delete` - :manual:`delete ` command reference in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-deleteOne.txt b/source/reference/method/MongoDBCollection-deleteOne.txt index 43209ebd..8013193f 100644 --- a/source/reference/method/MongoDBCollection-deleteOne.txt +++ b/source/reference/method/MongoDBCollection-deleteOne.txt @@ -131,6 +131,6 @@ See Also - :phpmethod:`MongoDB\Collection::deleteMany()` - :phpmethod:`MongoDB\Collection::bulkWrite()` -- :doc:`/tutorial/crud` +- :ref:`php-write-delete` - :manual:`delete ` command reference in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-dropIndex.txt b/source/reference/method/MongoDBCollection-dropIndex.txt index d1aa937c..c8c6e643 100644 --- a/source/reference/method/MongoDBCollection-dropIndex.txt +++ b/source/reference/method/MongoDBCollection-dropIndex.txt @@ -122,7 +122,7 @@ See Also -------- - :phpmethod:`MongoDB\Collection::dropIndexes()` -- :doc:`/tutorial/indexes` +- :ref:`php-indexes` - :manual:`dropIndexes ` command reference in the MongoDB manual - :manual:`Index documentation ` in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-dropIndexes.txt b/source/reference/method/MongoDBCollection-dropIndexes.txt index 32c1c134..fc7bc1c2 100644 --- a/source/reference/method/MongoDBCollection-dropIndexes.txt +++ b/source/reference/method/MongoDBCollection-dropIndexes.txt @@ -122,7 +122,7 @@ See Also -------- - :phpmethod:`MongoDB\Collection::dropIndex()` -- :doc:`/tutorial/indexes` +- :ref:`php-indexes` - :manual:`dropIndexes ` command reference in the MongoDB manual - :manual:`Index documentation ` in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-getNamespace.txt b/source/reference/method/MongoDBCollection-getNamespace.txt index 4003fbd8..3b055c7b 100644 --- a/source/reference/method/MongoDBCollection-getNamespace.txt +++ b/source/reference/method/MongoDBCollection-getNamespace.txt @@ -15,8 +15,9 @@ Definition .. phpmethod:: MongoDB\Collection::getNamespace() - Returns the :term:`namespace` of the collection. A namespace is the canonical - name of an index or collection in MongoDB. + Returns the :manual:`namespace ` + of the collection. A namespace is the canonical name of an index or collection + in MongoDB. .. code-block:: php diff --git a/source/reference/method/MongoDBCollection-insertMany.txt b/source/reference/method/MongoDBCollection-insertMany.txt index bcaec509..8362558e 100644 --- a/source/reference/method/MongoDBCollection-insertMany.txt +++ b/source/reference/method/MongoDBCollection-insertMany.txt @@ -157,6 +157,6 @@ See Also - :phpmethod:`MongoDB\Collection::insertOne()` - :phpmethod:`MongoDB\Collection::bulkWrite()` -- :doc:`/tutorial/crud` +- :ref:`php-write-insert` - :manual:`insert ` command reference in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-insertOne.txt b/source/reference/method/MongoDBCollection-insertOne.txt index d4b0d0de..b3bc98da 100644 --- a/source/reference/method/MongoDBCollection-insertOne.txt +++ b/source/reference/method/MongoDBCollection-insertOne.txt @@ -131,6 +131,6 @@ See Also - :phpmethod:`MongoDB\Collection::insertMany()` - :phpmethod:`MongoDB\Collection::bulkWrite()` -- :doc:`/tutorial/crud` +- :ref:`php-write-insert` - :manual:`insert ` command reference in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-listIndexes.txt b/source/reference/method/MongoDBCollection-listIndexes.txt index b65b228b..c6d9d474 100644 --- a/source/reference/method/MongoDBCollection-listIndexes.txt +++ b/source/reference/method/MongoDBCollection-listIndexes.txt @@ -128,7 +128,7 @@ The output would then resemble: See Also -------- -- :doc:`/tutorial/indexes` +- :ref:`php-indexes` - :manual:`listIndexes ` command reference in the MongoDB manual - :manual:`Index documentation ` in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-replaceOne.txt b/source/reference/method/MongoDBCollection-replaceOne.txt index 7a5444a1..b774fcdc 100644 --- a/source/reference/method/MongoDBCollection-replaceOne.txt +++ b/source/reference/method/MongoDBCollection-replaceOne.txt @@ -161,6 +161,6 @@ See Also - :phpmethod:`MongoDB\Collection::updateMany()` - :phpmethod:`MongoDB\Collection::updateOne()` - :phpmethod:`MongoDB\Collection::bulkWrite()` -- :doc:`/tutorial/crud` +- :ref:`php-write-replace` - :manual:`update ` command reference in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-updateMany.txt b/source/reference/method/MongoDBCollection-updateMany.txt index 0ada743b..e2c95b9b 100644 --- a/source/reference/method/MongoDBCollection-updateMany.txt +++ b/source/reference/method/MongoDBCollection-updateMany.txt @@ -158,6 +158,6 @@ See Also - :phpmethod:`MongoDB\Collection::replaceOne()` - :phpmethod:`MongoDB\Collection::updateOne()` - :phpmethod:`MongoDB\Collection::bulkWrite()` -- :doc:`/tutorial/crud` +- :ref:`php-write-update` - :manual:`update ` command reference in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-updateOne.txt b/source/reference/method/MongoDBCollection-updateOne.txt index 42877e73..27000edc 100644 --- a/source/reference/method/MongoDBCollection-updateOne.txt +++ b/source/reference/method/MongoDBCollection-updateOne.txt @@ -160,6 +160,6 @@ See Also - :phpmethod:`MongoDB\Collection::replaceOne()` - :phpmethod:`MongoDB\Collection::updateMany()` - :phpmethod:`MongoDB\Collection::bulkWrite()` -- :doc:`/tutorial/crud` +- :ref:`php-write-update` - :manual:`update ` command reference in the MongoDB manual diff --git a/source/reference/method/MongoDBCollection-withOptions.txt b/source/reference/method/MongoDBCollection-withOptions.txt index 8123904b..0b9531ac 100644 --- a/source/reference/method/MongoDBCollection-withOptions.txt +++ b/source/reference/method/MongoDBCollection-withOptions.txt @@ -37,7 +37,7 @@ Parameters * - codec - MongoDB\\Codec\\DocumentCodec - - The default :doc:`codec ` to use for collection + - The default :doc:`codec ` to use for collection operations. Defaults to the original collection's codec. .. versionadded:: 1.17 diff --git a/source/reference/method/MongoDBCollection__construct.txt b/source/reference/method/MongoDBCollection__construct.txt index a7480447..c9ee112d 100644 --- a/source/reference/method/MongoDBCollection__construct.txt +++ b/source/reference/method/MongoDBCollection__construct.txt @@ -51,7 +51,7 @@ Definition * - codec - MongoDB\\Codec\\DocumentCodec - - The default :doc:`codec ` to use for collection + - The default :doc:`codec ` to use for collection operations. .. versionadded:: 1.17 diff --git a/source/reference/method/MongoDBDatabase-selectCollection.txt b/source/reference/method/MongoDBDatabase-selectCollection.txt index b88179cd..237e38cf 100644 --- a/source/reference/method/MongoDBDatabase-selectCollection.txt +++ b/source/reference/method/MongoDBDatabase-selectCollection.txt @@ -43,7 +43,7 @@ Parameters * - codec - MongoDB\\Codec\\DocumentCodec - - The default :doc:`codec ` to use for collection + - The default :doc:`codec ` to use for collection operations. .. versionadded:: 1.17 diff --git a/source/reference/method/MongoDBDatabase-selectGridFSBucket.txt b/source/reference/method/MongoDBDatabase-selectGridFSBucket.txt index 2f42b6ff..5bd11d25 100644 --- a/source/reference/method/MongoDBDatabase-selectGridFSBucket.txt +++ b/source/reference/method/MongoDBDatabase-selectGridFSBucket.txt @@ -46,7 +46,7 @@ Parameters * - codec - MongoDB\\Codec\\DocumentCodec - - The default :doc:`codec ` to use for bucket methods + - The default :doc:`codec ` to use for bucket methods that return a file document (e.g. :phpmethod:`MongoDB\GridFS\Bucket::find()`). .. versionadded:: 1.17 diff --git a/source/reference/method/MongoDBGridFSBucket__construct.txt b/source/reference/method/MongoDBGridFSBucket__construct.txt index 1349e5f4..8bc64f09 100644 --- a/source/reference/method/MongoDBGridFSBucket__construct.txt +++ b/source/reference/method/MongoDBGridFSBucket__construct.txt @@ -57,7 +57,7 @@ Parameters * - codec - MongoDB\\Codec\\DocumentCodec - - The default :doc:`codec ` to use for bucket methods + - The default :doc:`codec ` to use for bucket methods that return a file document (e.g. :phpmethod:`MongoDB\GridFS\Bucket::find()`). .. versionadded:: 1.17 diff --git a/source/security.txt b/source/security.txt index 485595de..8c8e236b 100644 --- a/source/security.txt +++ b/source/security.txt @@ -135,7 +135,7 @@ the ``X.509`` authentication mechanism: :start-after: start-mongodb-X509-uri :end-before: end-mongodb-X509-uri -To learn more about X.509 authentication, see :ref:`php-x509` in +To learn more about X.509 authentication, see :ref:`php-mongodb-x509` in the Authentication guide. MONGODB-AWS @@ -155,7 +155,7 @@ attempts to retrieve your AWS credentials from the following sources, in the ord Each section shows how to authenticate with ``MONGODB-AWS`` when retrieving your AWS credentials from options passed to your client or the alternative external sources. -To learn more about authenticating with AWS, see :ref:`php-mongo-aws` in the +To learn more about authenticating with AWS, see :ref:`php-mongodb-aws` in the Authentication guide. MongoDB\\Client Credentials @@ -184,6 +184,10 @@ to authenticate with ``MONGODB-AWS``: :start-after: start-mongodb-aws-uri :end-before: end-mongodb-aws-uri +To learn more about authenticating with AWS by retrieving ``MongoDB\Client`` +credentials, see :ref:`php-mongodb-aws-credentials` in the Authentication +guide. + External Credentials ~~~~~~~~~~~~~~~~~~~~ @@ -214,7 +218,7 @@ request, ECS metadata, or EC2 instance metadata: To learn more about authenticating with AWS by obtaining external credentials, see the following sections in the Authentication guide: -- :ref:`php-mongo-aws-environment` -- :ref:`php-mongo-aws-assume-role` -- :ref:`php-mongo-aws-ecs` -- :ref:`php-mongo-aws-ec2` +- :ref:`php-mongodb-aws-env-vars` +- :ref:`php-mongodb-aws-oidc` +- :ref:`php-mongodb-aws-ecs` +- :ref:`php-mongodb-aws-ec2` diff --git a/source/security/authentication.txt b/source/security/authentication.txt index 13050e19..e03e9856 100644 --- a/source/security/authentication.txt +++ b/source/security/authentication.txt @@ -20,7 +20,7 @@ Authentication Mechanisms Overview -------- -This guide describes the mechanisms you can use in the {+driver-short+} to authenticate +This guide describes the mechanisms you can use in the {+library-short+} to authenticate users. .. important:: Percent-Encoding @@ -34,7 +34,7 @@ users. To learn more, see the following resources: - `RFC 3986 `__ - - `rawurlencode <{+php-manual+}/rawurlencode>`__ in the PHP manual + - :php:`rawurlencode ` in the PHP manual .. _php-scram-sha-256: @@ -174,8 +174,8 @@ these sources and use them to authenticate your PHP application. .. _php-mongodb-aws-credentials: -MongoDB\Client Credentials -~~~~~~~~~~~~~~~~~~~~~~~~~~ +MongoDB\\Client Credentials +~~~~~~~~~~~~~~~~~~~~~~~~~~~ First, the driver checks whether you passed AWS credentials to the ``MongoDB\Client`` constructor, either as as part of the connection @@ -355,7 +355,7 @@ connection option to ``'MONGODB-AWS'``. To view an example that sets the ``authMechanism`` option, see the :ref:`authMechanism example ` on this page. -.. _php-mongo-aws-ec2: +.. _php-mongodb-aws-ec2: EC2 Instance Metadata ~~~~~~~~~~~~~~~~~~~~~ diff --git a/source/tutorial.txt b/source/tutorial.txt index 4ea6c7fa..3102405c 100644 --- a/source/tutorial.txt +++ b/source/tutorial.txt @@ -9,8 +9,8 @@ Tutorials /tutorial/connecting /tutorial/server-selection - /tutorial/crud - /tutorial/codecs + /data-formats/crud + /data-formats/codecs /tutorial/collation /tutorial/commands /tutorial/custom-types diff --git a/source/tutorial/commands.txt b/source/tutorial/commands.txt index ff0de205..83dc6270 100644 --- a/source/tutorial/commands.txt +++ b/source/tutorial/commands.txt @@ -103,7 +103,7 @@ Specifying a Custom Read Preference ----------------------------------- Write commands, such as :manual:`createUser `, -can only be executed on a writable server (e.g. :term:`primary` replica set +can only be executed on a writable server (e.g. primary replica set member). Command helper methods in the |php-library|, such as :phpmethod:`MongoDB\Database::drop()`, know to apply their own :term:`read preference` if necessary. However, the :phpmethod:`MongoDB\Database::command()` diff --git a/source/upgrade.txt b/source/upgrade.txt index aab0d18d..730cc498 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -1,8 +1,8 @@ .. _php-upgrade: -======================= -Upgrade Driver Versions -======================= +======================== +Upgrade Library Versions +======================== .. contents:: On this page :local: @@ -20,28 +20,28 @@ Upgrade Driver Versions Overview -------- -On this page, you can learn how to upgrade your driver to a new version. This -page also includes the changes you must make to your application when you -upgrade to a new version of the {+php-library+}. +On this page, you can learn about the changes you must make to your application +when you upgrade to a new version of the {+php-library+}. This page also includes +how to upgrade your PHP extension to a new version. How to Upgrade -------------- Before you upgrade, perform the following actions: -- Ensure the new {+driver-short+} version is compatible with the {+mdb-server+} versions +- Ensure the new {+library-short+} version is compatible with the {+mdb-server+} versions your application connects to and the PHP version your application compiles with. For version compatibility information, see the :ref:`{+php-library+} Compatibility ` page. -- Address any breaking changes between the driver version +- Address any breaking changes between the library version your application is using and your planned upgrade version in the :ref:`Breaking Changes ` section. .. tip:: To ensure compatibility across {+mdb-server+} versions when - upgrading driver versions, use the :ref:`{+stable-api+} `. + upgrading library versions, use the :ref:`{+stable-api+} `. Major and minor versions of the PHP extension and library are in sync. This means you can run an upgrade command for the extension to also upgrade the PHP @@ -75,11 +75,11 @@ Breaking Changes ---------------- A breaking change is a change of a convention or a behavior starting in a specific -version of the driver. This type of change may prevent your application from working -properly if not addressed before upgrading the driver. +version of the library. This type of change may prevent your application from working +properly if not addressed before upgrading the library. -The breaking changes in this section are categorized by the driver version that introduced -them. When upgrading driver versions, address all the breaking changes between the current +The breaking changes in this section are categorized by the library version that introduced +them. When upgrading library versions, address all the breaking changes between the current and upgrade versions. For more information on release changes, see the release notes and associated @@ -88,12 +88,12 @@ JIRA tickets for each release on `GitHub `__. diff --git a/source/write/delete.txt b/source/write/delete.txt index c45f16dd..2dd0cec1 100644 --- a/source/write/delete.txt +++ b/source/write/delete.txt @@ -194,6 +194,6 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::deleteOne() <{+api+}/method/MongoDBCollection-deleteOne/>`__ -- `MongoDB\\Collection::deleteMany() <{+api+}/method/MongoDBCollection-deleteMany/>`__ -- `MongoDB\\DeleteResult <{+api+}/class/MongoDBDeleteResult/>`__ +- :phpmethod:`MongoDB\Collection::deleteOne()` +- :phpmethod:`MongoDB\Collection::deleteMany()` +- :phpclass:`MongoDB\DeleteResult` diff --git a/source/write/gridfs.txt b/source/write/gridfs.txt index 20bbc6dd..3415dc8f 100644 --- a/source/write/gridfs.txt +++ b/source/write/gridfs.txt @@ -58,7 +58,7 @@ chunks, each represented by a separate document in the ``chunks`` collection. It also creates a document in the ``files`` collection that contains a file ID, file name, and other file metadata. You can upload the file by passing a stream to the {+php-library+} to consume or creating a new stream and writing to it -directly. To learn more about streams, see `Streams <{+php-manual+}/book.stream.php>`__ +directly. To learn more about streams, see :php:`Streams ` in the PHP manual. View the following diagram to see how GridFS splits the files when uploaded to diff --git a/source/write/insert.txt b/source/write/insert.txt index 340c9410..1a32d551 100644 --- a/source/write/insert.txt +++ b/source/write/insert.txt @@ -35,7 +35,7 @@ Sample Data The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` database from the :atlas:`Atlas sample datasets `. To access this collection from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster -and assign the following value to your ``collection`` variable: +and assign the following value to your ``$collection`` variable: .. literalinclude:: /includes/write/insert.php :language: php @@ -158,9 +158,8 @@ insert operation bypasses document-level validation: Additional Information ---------------------- -.. TODO: - For runnable code examples of inserting documents with the {+php-library+}, see - :ref:`php-write`. +To view runnable code examples of inserting documents with the {+php-library+}, see +:ref:`php-write`. API Documentation ~~~~~~~~~~~~~~~~~ @@ -168,5 +167,5 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::insertOne() <{+api+}/method/MongoDBCollection-insertOne/>`__ -- `MongoDB\\Collection::insertMany() <{+api+}/method/MongoDBCollection-insertMany/>`__ \ No newline at end of file +- :phpmethod:`MongoDB\Collection::insertOne()` +- :phpmethod:`MongoDB\Collection::insertMany()` \ No newline at end of file diff --git a/source/write/replace.txt b/source/write/replace.txt index 8e7909d6..ec433ea2 100644 --- a/source/write/replace.txt +++ b/source/write/replace.txt @@ -206,5 +206,5 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::replaceOne() <{+api+}/method/MongoDBCollection-replaceOne/>`__ -- `MongoDB\\UpdateResult <{+api+}/class/MongoDBUpdateResult/>`__ +- :phpmethod:`MongoDB\Collection::replaceOne()` +- :phpclass:`MongoDB\UpdateResult` diff --git a/source/write/update.txt b/source/write/update.txt index e07bde61..8f80a2fe 100644 --- a/source/write/update.txt +++ b/source/write/update.txt @@ -31,7 +31,7 @@ Sample Data The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants`` database from the :atlas:`Atlas sample datasets `. To access this collection from your PHP application, instantiate a ``MongoDB\Client`` that connects to an Atlas cluster -and assign the following value to your ``collection`` variable: +and assign the following value to your ``$collection`` variable: .. literalinclude:: /includes/write/update.php :language: php @@ -224,6 +224,6 @@ API Documentation To learn more about any of the methods or types discussed in this guide, see the following API documentation: -- `MongoDB\\Collection::updateOne() <{+api+}/method/MongoDBCollection-updateOne>`__ -- `MongoDB\\Collection::updateMany() <{+api+}/method/MongoDBCollection-updateMany>`__ -- `MongoDB\\UpdateResult <{+api+}/class/MongoDBUpdateResult>`__ \ No newline at end of file +- :phpmethod:`MongoDB\Collection::updateOne()` +- :phpmethod:`MongoDB\Collection::updateMany()` +- :phpclass:`MongoDB\UpdateResult` \ No newline at end of file From 61a36a784e6c9800fbcfc28a092aac91f7309607 Mon Sep 17 00:00:00 2001 From: norareidy Date: Fri, 27 Sep 2024 16:50:44 -0400 Subject: [PATCH 148/149] build fix --- source/connect.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/connect.txt b/source/connect.txt index 30e22002..7bbdce1e 100644 --- a/source/connect.txt +++ b/source/connect.txt @@ -23,8 +23,8 @@ Connect to MongoDB :maxdepth: 1 /connect/client - /connect/connection-targets /connect/connection-options + /connect/connection-targets /connect/tls /connect/stable-api From 7ce2aa81f284ea342832a765bfdbf1960f1ea6d2 Mon Sep 17 00:00:00 2001 From: norareidy Date: Fri, 27 Sep 2024 17:13:01 -0400 Subject: [PATCH 149/149] php directives --- source/connect/connection-options.txt | 4 ++-- source/connect/stable-api.txt | 2 +- source/get-started/download-and-install.txt | 2 +- source/tutorial/commands.txt | 4 ++-- source/upgrade.txt | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/connect/connection-options.txt b/source/connect/connection-options.txt index 3c19fed2..8f123f94 100644 --- a/source/connect/connection-options.txt +++ b/source/connect/connection-options.txt @@ -213,7 +213,7 @@ Read Preference Options - Description * - :manual:`readPreference ` - - | **Data Type**: `MongoDB\\Driver\\ReadPreference `__ + - | **Data Type**: :php:`MongoDB\Driver\ReadPreference ` | **MongoDB\\Client Example**: ``$uriOptions = ['readPreference' => 'secondaryPreferred'];`` | **Connection URI Example**: ``readPreference=secondaryPreferred`` @@ -325,4 +325,4 @@ API documentation: For more information about the ``MongoDB\Driver\ReadPreference`` class, see the following {+extension-short+} API documentation: -- `MongoDB\\Driver\\ReadPreference `__ \ No newline at end of file +- :php:`MongoDB\Driver\ReadPreference ` \ No newline at end of file diff --git a/source/connect/stable-api.txt b/source/connect/stable-api.txt index ff2b96cd..e00eeb55 100644 --- a/source/connect/stable-api.txt +++ b/source/connect/stable-api.txt @@ -116,4 +116,4 @@ API documentation: For more information about the ``MongoDB\Driver\ServerApi`` class, see the following {+extension-short+} API documentation: -- `MongoDB\\Driver\\ServerApi `__ \ No newline at end of file +- :php:`MongoDB\Driver\ServerApi ` \ No newline at end of file diff --git a/source/get-started/download-and-install.txt b/source/get-started/download-and-install.txt index 356830fc..d9f15d67 100644 --- a/source/get-started/download-and-install.txt +++ b/source/get-started/download-and-install.txt @@ -19,7 +19,7 @@ Download and Install Before you begin developing, ensure that you have the following dependencies installed on your local machine: - - `PHP `__ version 7.4 or later + - :php:`PHP ` version 7.4 or later - `Composer `__ version 2.0 or later .. step:: Install the MongoDB PHP extension diff --git a/source/tutorial/commands.txt b/source/tutorial/commands.txt index 83dc6270..de55d0a1 100644 --- a/source/tutorial/commands.txt +++ b/source/tutorial/commands.txt @@ -96,8 +96,8 @@ The output might resemble the following: ` method in the extension detects such a response, it will construct an iterable command cursor and return it instead of the raw result document. If necessary, raw result documents can - still be observed using `command monitoring - `_. + still be observed using :php:`command monitoring + `. Specifying a Custom Read Preference ----------------------------------- diff --git a/source/upgrade.txt b/source/upgrade.txt index 730cc498..2ea4cedf 100644 --- a/source/upgrade.txt +++ b/source/upgrade.txt @@ -67,7 +67,7 @@ application's directory: composer require mongodb/mongodb: Detailed installation instructions may be found in the -:php:`PHP.net documentation `. +:php:`PHP.net documentation `. .. _php-breaking-changes: