From 3d8d0954925873020e08873b4540ceeb8f80996f Mon Sep 17 00:00:00 2001
From: Rea Rustagi <85902999+rustagir@users.noreply.github.com>
Date: Tue, 4 Mar 2025 09:48:48 -0500
Subject: [PATCH 1/9] DOCSP-48028: v5.2 release (#3297)
* DOCSP-48028: v5.2 release
* wip
* wip
* add keyword
---
docs/compatibility.txt | 8 ++++++-
docs/filesystems.txt | 4 ++--
docs/fundamentals/aggregation-builder.txt | 22 -------------------
.../framework-compatibility-laravel.rst | 10 +++++++++
docs/query-builder.txt | 2 +-
docs/quick-start.txt | 2 +-
docs/quick-start/download-and-install.txt | 2 +-
docs/user-authentication.txt | 5 +++--
8 files changed, 25 insertions(+), 30 deletions(-)
diff --git a/docs/compatibility.txt b/docs/compatibility.txt
index fd3e2da02..9ee891e20 100644
--- a/docs/compatibility.txt
+++ b/docs/compatibility.txt
@@ -15,7 +15,7 @@ Compatibility
:class: singlecol
.. meta::
- :keywords: laravel 9, laravel 10, laravel 11, 4.0, 4.1, 4.2, 5.0, 5.1
+ :keywords: laravel 9, laravel 10, laravel 11, laravel 12, 4.0, 4.1, 4.2, 5.0, 5.1, 5.2
Laravel Compatibility
---------------------
@@ -28,3 +28,9 @@ the {+odm-short+} that you can use together.
To find compatibility information for unmaintained versions of the {+odm-short+},
see `Laravel Version Compatibility <{+mongodb-laravel-gh+}/blob/3.9/README.md#installation>`__
on GitHub.
+
+PHP Driver Compatibility
+------------------------
+
+To use {+odm-long+} v5.2 or later, you must install v1.21 of the
+{+php-library+} and {+php-extension+}.
diff --git a/docs/filesystems.txt b/docs/filesystems.txt
index 3ec7ee41f..c62853f58 100644
--- a/docs/filesystems.txt
+++ b/docs/filesystems.txt
@@ -79,7 +79,7 @@ You can configure the following settings in ``config/filesystems.php``:
* - ``throw``
- If ``true``, exceptions are thrown when an operation cannot be performed. If ``false``,
- operations return ``true`` on success and ``false`` on error. Defaults to ``false``.
+ operations return ``true`` on success and ``false`` on error. Defaults to ``false``.
You can also use a factory or a service name to create an instance of ``MongoDB\GridFS\Bucket``.
In this case, the options ``connection`` and ``database`` are ignored:
@@ -133,7 +133,7 @@ metadata, including the file name and a unique ObjectId. If multiple documents
share the same file name, they are considered "revisions" and further
distinguished by creation timestamps.
-The Laravel MongoDB integration uses the GridFS Flysystem adapter. It interacts
+{+odm-long+} uses the GridFS Flysystem adapter. It interacts
with file revisions in the following ways:
- Reading a file reads the last revision of this file name
diff --git a/docs/fundamentals/aggregation-builder.txt b/docs/fundamentals/aggregation-builder.txt
index 3169acfeb..9ae31f0c1 100644
--- a/docs/fundamentals/aggregation-builder.txt
+++ b/docs/fundamentals/aggregation-builder.txt
@@ -37,7 +37,6 @@ The {+odm-long+} aggregation builder lets you build aggregation stages and
aggregation pipelines. The following sections show examples of how to use the
aggregation builder to create the stages of an aggregation pipeline:
-- :ref:`laravel-add-aggregation-dependency`
- :ref:`laravel-build-aggregation`
- :ref:`laravel-aggregation-examples`
- :ref:`laravel-create-custom-operator-factory`
@@ -49,27 +48,6 @@ aggregation builder to create the stages of an aggregation pipeline:
aggregation builder, see :ref:`laravel-query-builder-aggregations` in the
Query Builder guide.
-.. _laravel-add-aggregation-dependency:
-
-Add the Aggregation Builder Dependency
---------------------------------------
-
-The aggregation builder is part of the {+agg-builder-package-name+} package.
-You must add this package as a dependency to your project to use it. Run the
-following command to add the aggregation builder dependency to your
-application:
-
-.. code-block:: bash
-
- composer require {+agg-builder-package-name+}:{+agg-builder-version+}
-
-When the installation completes, verify that the ``composer.json`` file
-includes the following line in the ``require`` object:
-
-.. code-block:: json
-
- "{+agg-builder-package-name+}": "{+agg-builder-version+}",
-
.. _laravel-build-aggregation:
Create Aggregation Stages
diff --git a/docs/includes/framework-compatibility-laravel.rst b/docs/includes/framework-compatibility-laravel.rst
index 16c405e21..c642a6763 100644
--- a/docs/includes/framework-compatibility-laravel.rst
+++ b/docs/includes/framework-compatibility-laravel.rst
@@ -3,21 +3,31 @@
:stub-columns: 1
* - {+odm-long+} Version
+ - Laravel 12.x
- Laravel 11.x
- Laravel 10.x
- Laravel 9.x
+ * - 5.2
+ - ✓
+ - ✓
+ - ✓
+ -
+
* - 4.2 to 5.1
+ -
- ✓
- ✓
-
* - 4.1
+ -
-
- ✓
-
* - 4.0
+ -
-
- ✓
-
diff --git a/docs/query-builder.txt b/docs/query-builder.txt
index 76a0d144a..c641323dc 100644
--- a/docs/query-builder.txt
+++ b/docs/query-builder.txt
@@ -227,7 +227,7 @@ value greater than ``8.5`` and a ``year`` value of less than
.. tip::
- For compatibility with Laravel, Laravel MongoDB v5.1 supports both arrow
+ For compatibility with Laravel, {+odm-long+} v5.1 supports both arrow
(``->``) and dot (``.``) notation to access nested fields in a query
filter. The preceding example uses dot notation to query the ``imdb.rating``
nested field, which is the recommended syntax.
diff --git a/docs/quick-start.txt b/docs/quick-start.txt
index 1d188ad84..83b0c3937 100644
--- a/docs/quick-start.txt
+++ b/docs/quick-start.txt
@@ -47,7 +47,7 @@ read and write operations on the data.
MongoDB University Learning Byte.
If you prefer to connect to MongoDB by using the {+php-library+} without
- Laravel, see `Connecting to MongoDB `__
+ Laravel, see `Connect to MongoDB `__
in the {+php-library+} documentation.
The {+odm-short+} extends the Laravel Eloquent and Query Builder syntax to
diff --git a/docs/quick-start/download-and-install.txt b/docs/quick-start/download-and-install.txt
index 696861a43..293425791 100644
--- a/docs/quick-start/download-and-install.txt
+++ b/docs/quick-start/download-and-install.txt
@@ -31,7 +31,7 @@ to a Laravel web application.
.. tip::
As an alternative to the following installation steps, you can use Laravel Herd
- to install MongoDB and configure a Laravel MongoDB development environment. For
+ to install MongoDB and configure a development environment for {+odm-long+}. For
more information about using Laravel Herd with MongoDB, see the following resources:
- `Installing MongoDB via Herd Pro
diff --git a/docs/user-authentication.txt b/docs/user-authentication.txt
index 88b0da603..63e883d13 100644
--- a/docs/user-authentication.txt
+++ b/docs/user-authentication.txt
@@ -224,7 +224,7 @@ to the ``guards`` array:
],
],
-Use Laravel Passport with Laravel MongoDB
+Use Laravel Passport with {+odm-long+}
`````````````````````````````````````````
After installing Laravel Passport, you must enable Passport compatibility with MongoDB by
@@ -300,4 +300,5 @@ Additional Information
To learn more about user authentication, see `Authentication `__
in the Laravel documentation.
-To learn more about Eloquent models, see the :ref:`laravel-eloquent-model-class` guide.
\ No newline at end of file
+To learn more about Eloquent models, see the
+:ref:`laravel-eloquent-model-class` guide.
From f06d944955fed946fdf94f0a6f01fa48142b1357 Mon Sep 17 00:00:00 2001
From: Rea Rustagi <85902999+rustagir@users.noreply.github.com>
Date: Tue, 4 Mar 2025 10:56:29 -0500
Subject: [PATCH 2/9] Merges the read operation reorganization into 5.2 (#3301)
* DOCSP-35945: read operations reorg (#3293)
* DOCSP-35945: read operations reorg
* skip
* small fixes
* small fixes
* fixes - RM and moved a section
* link fic
* Fix releasing from development branch (#3299)
---------
Co-authored-by: MongoDB PHP Bot <162451593+mongodb-php-bot@users.noreply.github.com>
Co-authored-by: Andreas Braun
---
.github/workflows/release.yml | 2 +-
docs/fundamentals/read-operations.txt | 749 +++---------------
.../read-operations/modify-results.txt | 227 ++++++
.../read-operations/read-pref.txt | 141 ++++
.../fundamentals/read-operations/retrieve.txt | 304 +++++++
.../read-operations/search-text.txt | 157 ++++
docs/fundamentals/write-operations.txt | 3 +-
.../before-you-get-started.rst | 15 +
8 files changed, 960 insertions(+), 638 deletions(-)
create mode 100644 docs/fundamentals/read-operations/modify-results.txt
create mode 100644 docs/fundamentals/read-operations/read-pref.txt
create mode 100644 docs/fundamentals/read-operations/retrieve.txt
create mode 100644 docs/fundamentals/read-operations/search-text.txt
create mode 100644 docs/includes/fundamentals/read-operations/before-you-get-started.rst
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4afbe78f1..bc60a79cc 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -32,7 +32,7 @@ jobs:
run: |
echo RELEASE_VERSION=${{ inputs.version }} >> $GITHUB_ENV
echo RELEASE_BRANCH=$(echo ${{ inputs.version }} | cut -d '.' -f-2) >> $GITHUB_ENV
- echo DEV_BRANCH=$(echo ${{ inputs.version }} | cut -d '.' - f-1).x >> $GITHUB_ENV
+ echo DEV_BRANCH=$(echo ${{ inputs.version }} | cut -d '.' -f-1).x >> $GITHUB_ENV
- name: "Ensure release tag does not already exist"
run: |
diff --git a/docs/fundamentals/read-operations.txt b/docs/fundamentals/read-operations.txt
index f3b02c5ec..367e2d38d 100644
--- a/docs/fundamentals/read-operations.txt
+++ b/docs/fundamentals/read-operations.txt
@@ -10,7 +10,14 @@ Read Operations
:values: tutorial
.. meta::
- :keywords: find one, find many, code example
+ :keywords: find one, find many, skip, limit, paginate, string, code example
+
+.. toctree::
+
+ Retrieve Data
+ Search Text
+ Modify Query Results
+ Set Read Preference
.. contents:: On this page
:local:
@@ -21,697 +28,169 @@ Read Operations
Overview
--------
-In this guide, you can learn how to use {+odm-long+} to perform **find operations**
-on your MongoDB collections. Find operations allow you to retrieve documents based on
-criteria that you specify.
-
-This guide shows you how to perform the following tasks:
-
-- :ref:`laravel-retrieve-matching`
-- :ref:`laravel-retrieve-all`
-- :ref:`laravel-retrieve-text-search`
-- :ref:`Modify Find Operation Behavior `
-
-Before You Get Started
-----------------------
-
-To run the code examples in this guide, complete the :ref:`Quick Start `
-tutorial. This tutorial provides instructions on setting up a MongoDB Atlas instance with
-sample data and creating the following files in your Laravel web application:
-
-- ``Movie.php`` file, which contains a ``Movie`` model to represent documents in the ``movies``
- collection
-- ``MovieController.php`` file, which contains a ``show()`` function to run database operations
-- ``browse_movies.blade.php`` file, which contains HTML code to display the results of database
- operations
-
-The following sections describe how to edit the files in your Laravel application to run
-the find operation code examples and view the expected output.
-
-.. _laravel-retrieve-matching:
-
-Retrieve Documents that Match a Query
--------------------------------------
-
-You can use Laravel's Eloquent object-relational mapper (ORM) to create models
-that represent MongoDB collections and chain methods on them to specify
-query criteria.
-
-To retrieve documents that match a set of criteria, call the ``where()``
-method on the collection's corresponding Eloquent model, then pass a query
-filter to the method.
-
-A query filter specifies field value requirements and instructs the find
-operation to return only documents that meet these requirements.
-
-You can use one of the following ``where()`` method calls to build a query:
-
-- ``where('', )`` builds a query that matches documents in
- which the target field has the exact specified value
-
-- ``where('', '', )`` builds a query
- that matches documents in which the target field's value meets the comparison
- criteria
-
-To apply multiple sets of criteria to the find operation, you can chain a series
-of ``where()`` methods together.
-
-After building your query by using the ``where()`` method, chain the ``get()``
-method to retrieve the query results.
-
-This example calls two ``where()`` methods on the ``Movie`` Eloquent model to
-retrieve documents that meet the following criteria:
-
-- ``year`` field has a value of ``2010``
-- ``imdb.rating`` nested field has a value greater than ``8.5``
-
-.. tabs::
-
- .. tab:: Query Syntax
- :tabid: query-syntax
-
- Use the following syntax to specify the query:
-
- .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-query
- :end-before: end-query
-
- .. tab:: Controller Method
- :tabid: controller
-
- To see the query results in the ``browse_movies`` view, edit the ``show()`` function
- in the ``MovieController.php`` file to resemble the following code:
-
- .. io-code-block::
- :copyable: true
-
- .. input::
- :language: php
-
- class MovieController
- {
- public function show()
- {
- $movies = Movie::where('year', 2010)
- ->where('imdb.rating', '>', 8.5)
- ->get();
-
- return view('browse_movies', [
- 'movies' => $movies
- ]);
- }
- }
-
- .. output::
- :language: none
- :visible: false
-
- Title: Inception
- Year: 2010
- Runtime: 148
- IMDB Rating: 8.8
- IMDB Votes: 1294646
- Plot: A thief who steals corporate secrets through use of dream-sharing
- technology is given the inverse task of planting an idea into the mind of a CEO.
-
- Title: Senna
- Year: 2010
- Runtime: 106
- IMDB Rating: 8.6
- IMDB Votes: 41904
- Plot: A documentary on Brazilian Formula One racing driver Ayrton Senna, who won the
- F1 world championship three times before his death at age 34.
-
-To learn how to query by using the Laravel query builder instead of the
-Eloquent ORM, see the :ref:`laravel-query-builder` page.
-
-Match Array Field Elements
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can specify a query filter to match array field elements when
-retrieving documents. If your documents contain an array field, you can
-match documents based on if the value contains all or some specified
-array elements.
-
-You can use one of the following ``where()`` method calls to build a
-query on an array field:
-
-- ``where('', )`` builds a query that matches documents in
- which the array field value is exactly the specified array
+In this guide, you can see code templates of common
+methods that you can use to read data from MongoDB by using
+{+odm-long+}.
-- ``where('', 'in', )`` builds a query
- that matches documents in which the array field value contains one or
- more of the specified array elements
-
-After building your query by using the ``where()`` method, chain the ``get()``
-method to retrieve the query results.
-
-Select from the following :guilabel:`Exact Array Match` and
-:guilabel:`Element Match` tabs to view the query syntax for each pattern:
-
-.. tabs::
-
- .. tab:: Exact Array Match
- :tabid: exact-array
-
- This example retrieves documents in which the ``countries`` array is
- exactly ``['Indonesia', 'Canada']``:
-
- .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-exact-array
- :end-before: end-exact-array
-
- .. tab:: Element Match
- :tabid: element-match
-
- This example retrieves documents in which the ``countries`` array
- contains one of the values in the array ``['Canada', 'Egypt']``:
-
- .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-elem-match
- :end-before: end-elem-match
-
-To learn how to query array fields by using the Laravel query builder instead of the
-Eloquent ORM, see the :ref:`laravel-query-builder-elemMatch` section in
-the Query Builder guide.
-
-.. _laravel-retrieve-all:
+.. tip::
-Retrieve All Documents in a Collection
---------------------------------------
+ To learn more about any of the methods included in this guide,
+ see the links provided in each section.
-You can retrieve all documents in a collection by omitting the query filter.
-To return the documents, call the ``get()`` method on an Eloquent model that
-represents your collection. Alternatively, you can use the ``get()`` method's
-alias ``all()`` to perform the same operation.
+Find One
+--------
-Use the following syntax to run a find operation that matches all documents:
+The following code shows how to retrieve the first matching document
+from a collection:
.. code-block:: php
- $movies = Movie::get();
-
-.. warning::
-
- The ``movies`` collection in the Atlas sample dataset contains a large amount of data.
- Retrieving and displaying all documents in this collection might cause your web
- application to time out.
-
- To avoid this issue, specify a document limit by using the ``take()`` method. For
- more information about ``take()``, see the :ref:`laravel-modify-find` section of this
- guide.
-
-.. _laravel-retrieve-text-search:
-
-Search Text Fields
-------------------
-
-A text search retrieves documents that contain a **term** or a **phrase** in the
-text-indexed fields. A term is a sequence of characters that excludes
-whitespace characters. A phrase is a sequence of terms with any number
-of whitespace characters.
+ SampleModel::where('', '')
+ ->first();
-.. note::
+To view a runnable example that finds one document, see the
+:ref:`laravel-find-one-usage` usage example.
- Before you can perform a text search, you must create a :manual:`text
- index ` on
- the text-valued field. To learn more about creating
- indexes, see the :ref:`laravel-eloquent-indexes` section of the
- Schema Builder guide.
+To learn more about retrieving documents and the ``first()`` method, see
+the :ref:`laravel-fundamentals-read-retrieve` guide.
-You can perform a text search by using the :manual:`$text
-` operator followed
-by the ``$search`` field in your query filter that you pass to the
-``where()`` method. The ``$text`` operator performs a text search on the
-text-indexed fields. The ``$search`` field specifies the text to search for.
+Find Multiple
+-------------
-After building your query by using the ``where()`` method, chain the ``get()``
-method to retrieve the query results.
+The following code shows how to retrieve all documents that match a
+query filter from a collection:
-This example calls the ``where()`` method on the ``Movie`` Eloquent model to
-retrieve documents in which the ``plot`` field contains the phrase
-``"love story"``. To perform this text search, the collection must have
-a text index on the ``plot`` field.
-
-.. tabs::
-
- .. tab:: Query Syntax
- :tabid: query-syntax
+.. code-block:: php
- Use the following syntax to specify the query:
+ SampleModel::where('', '')
+ ->get();
- .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-text
- :end-before: end-text
+To view a runnable example that finds documents, see the
+:ref:`laravel-find-usage` usage example.
- .. tab:: Controller Method
- :tabid: controller
+To learn more about retrieving documents, see the
+:ref:`laravel-fundamentals-read-retrieve` guide.
- To see the query results in the ``browse_movies`` view, edit the ``show()`` function
- in the ``MovieController.php`` file to resemble the following code:
+Return All Documents
+--------------------
- .. io-code-block::
- :copyable: true
+The following code shows how to retrieve all documents from a
+collection:
- .. input::
- :language: php
+.. code-block:: php
- class MovieController
- {
- public function show()
- {
- $movies = Movie::where('$text', ['$search' => '"love story"'])
- ->get();
+ SampleModel::get();
- return view('browse_movies', [
- 'movies' => $movies
- ]);
- }
- }
+ // Or, use the all() method.
+ SampleModel::all();
- .. output::
- :language: none
- :visible: false
+To view a runnable example that finds documents, see the
+:ref:`laravel-find-usage` usage example.
- Title: Cafè de Flore
- Year: 2011
- Runtime: 120
- IMDB Rating: 7.4
- IMDB Votes: 9663
- Plot: A love story between a man and woman ...
+To learn more about retrieving documents, see the
+:ref:`laravel-fundamentals-read-retrieve` guide.
- Title: Paheli
- Year: 2005
- Runtime: 140
- IMDB Rating: 6.7
- IMDB Votes: 8909
- Plot: A folk tale - supernatural love story about a ghost ...
+Search Text
+-----------
- Title: Por un puèado de besos
- Year: 2014
- Runtime: 98
- IMDB Rating: 6.1
- IMDB Votes: 223
- Plot: A girl. A boy. A love story ...
-
- ...
-
-A text search assigns a numerical :manual:`text score ` to indicate how closely
-each result matches the string in your query filter. You can sort the
-results by relevance by using the ``orderBy()`` method to sort on the
-``textScore`` metadata field. You can access this metadata by using the
-:manual:`$meta ` operator:
-
-.. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-text-relevance
- :end-before: end-text-relevance
- :emphasize-lines: 2
+The following code shows how to perform a full-text search on a string
+field in a collection's documents:
-.. tip::
+.. code-block:: php
- To learn more about the ``orderBy()`` method, see the
- :ref:`laravel-sort` section of this guide.
+ SampleModel::where('$text', ['$search' => ''])
+ ->get();
-.. _laravel-modify-find:
+To learn more about searching on text fields, see the
+:ref:`laravel-retrieve-text-search` guide.
-Modify Behavior
+Count Documents
---------------
-You can modify the results of a find operation by chaining more methods
-to ``where()``.
-
-The following sections demonstrate how to modify the behavior of the ``where()``
-method:
-
-- :ref:`laravel-skip-limit` uses the ``skip()`` method to set the number of documents
- to skip and the ``take()`` method to set the total number of documents to return
-- :ref:`laravel-sort` uses the ``orderBy()`` method to return query
- results in a specified order based on field values
-- :ref:`laravel-retrieve-one` uses the ``first()`` method to return the first document
- that matches the query filter
-- :ref:`laravel-read-pref` uses the ``readPreference()`` method to direct the query
- to specific replica set members
-
-.. _laravel-skip-limit:
-
-Skip and Limit Results
-~~~~~~~~~~~~~~~~~~~~~~
-
-This example queries for documents in which the ``year`` value is ``1999``.
-The operation skips the first ``2`` matching documents and outputs a total of ``3``
-documents.
-
-.. tabs::
-
- .. tab:: Query Syntax
- :tabid: query-syntax
-
- Use the following syntax to specify the query:
-
- .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-skip-limit
- :end-before: end-skip-limit
-
- .. tab:: Controller Method
- :tabid: controller
+The following code shows how to count documents in a collection:
- To see the query results in the ``browse_movies`` view, edit the ``show()`` function
- in the ``MovieController.php`` file to resemble the following code:
-
- .. io-code-block::
- :copyable: true
-
- .. input::
- :language: php
-
- class MovieController
- {
- public function show()
- {
- $movies = Movie::where('year', 1999)
- ->skip(2)
- ->take(3)
- ->get();
-
- return view('browse_movies', [
- 'movies' => $movies
- ]);
- }
- }
-
- .. output::
- :language: none
- :visible: false
-
- Title: Three Kings
- Year: 1999
- Runtime: 114
- IMDB Rating: 7.2
- IMDB Votes: 130677
- Plot: In the aftermath of the Persian Gulf War, 4 soldiers set out to steal gold
- that was stolen from Kuwait, but they discover people who desperately need their help.
-
- Title: Toy Story 2
- Year: 1999
- Runtime: 92
- IMDB Rating: 7.9
- IMDB Votes: 346655
- Plot: When Woody is stolen by a toy collector, Buzz and his friends vow to rescue him,
- but Woody finds the idea of immortality in a museum tempting.
-
- Title: Beowulf
- Year: 1999
- Runtime: 95
- IMDB Rating: 4
- IMDB Votes: 9296
- Plot: A sci-fi update of the famous 6th Century poem. In a besieged land, Beowulf must
- battle against the hideous creature Grendel and his vengeance seeking mother.
-
-.. _laravel-sort:
-
-Sort Query Results
-~~~~~~~~~~~~~~~~~~
-
-To order query results based on the values of specified fields, use the ``where()`` method
-followed by the ``orderBy()`` method.
-
-You can set an **ascending** or **descending** sort direction on
-results. By default, the ``orderBy()`` method sets an ascending sort on
-the supplied field name, but you can explicitly specify an ascending
-sort by passing ``"asc"`` as the second parameter. To
-specify a descending sort, pass ``"desc"`` as the second parameter.
-
-If your documents contain duplicate values in a specific field, you can
-handle the tie by specifying more fields to sort on. This ensures consistent
-results if the other fields contain unique values.
-
-This example queries for documents in which the value of the ``countries`` field contains
-``"Indonesia"`` and orders results first by an ascending sort on the
-``year`` field, then a descending sort on the ``title`` field.
-
-.. tabs::
-
- .. tab:: Query Syntax
- :tabid: query-syntax
-
- Use the following syntax to specify the query:
-
- .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-sort
- :end-before: end-sort
-
- .. tab:: Controller Method
- :tabid: controller
-
- To see the query results in the ``browse_movies`` view, edit the ``show()`` function
- in the ``MovieController.php`` file to resemble the following code:
-
- .. io-code-block::
- :copyable: true
-
- .. input::
- :language: php
-
- class MovieController
- {
- public function show()
- {
- $movies = Movie::where('countries', 'Indonesia')
- ->orderBy('year')
- ->orderBy('title', 'desc')
- ->get();
-
- return view('browse_movies', [
- 'movies' => $movies
- ]);
- }
- }
-
- .. output::
- :language: none
- :visible: false
-
- Title: Joni's Promise
- Year: 2005
- Runtime: 83
- IMDB Rating: 7.6
- IMDB Votes: 702
- Plot: A film delivery man promises ...
-
- Title: Gie
- Year: 2005
- Runtime: 147
- IMDB Rating: 7.5
- IMDB Votes: 470
- Plot: Soe Hok Gie is an activist who lived in the sixties ...
-
- Title: Requiem from Java
- Year: 2006
- Runtime: 120
- IMDB Rating: 6.6
- IMDB Votes: 316
- Plot: Setyo (Martinus Miroto) and Siti (Artika Sari Dewi)
- are young married couple ...
-
- ...
+.. code-block:: php
-.. tip::
+ SampleModel::count();
- To learn more about sorting, see the following resources:
+ // You can also count documents that match a filter.
+ SampleModel::where('', '')
+ ->count();
- - :manual:`Natural order `
- in the {+server-docs-name+} glossary
- - `Ordering, Grouping, Limit, and Offset `__
- in the Laravel documentation
+To view a runnable example that counts documents, see the
+:ref:`laravel-count-usage` usage example.
-.. _laravel-retrieve-one:
+Retrieve Distinct Values
+------------------------
-Return the First Result
-~~~~~~~~~~~~~~~~~~~~~~~
+The following code shows how to retrieve the distinct values of a
+specified field:
-To retrieve the first document that matches a set of criteria, use the ``where()`` method
-followed by the ``first()`` method.
+.. code-block:: php
-Chain the ``orderBy()`` method to ``first()`` to get consistent results when you query on a unique
-value. If you omit the ``orderBy()`` method, MongoDB returns the matching documents according to
-the documents' natural order, or as they appear in the collection.
+ SampleModel::select('')
+ ->distinct()
+ ->get();
-This example queries for documents in which the value of the ``runtime`` field is
-``30`` and returns the first matching document according to the value of the ``_id``
-field.
+To view a runnable example that returns distinct field values, see the
+:ref:`laravel-distinct-usage` usage example.
-.. tabs::
+Skip Results
+------------
- .. tab:: Query Syntax
- :tabid: query-syntax
+The following code shows how to skip a specified number of documents
+returned from MongoDB:
- Use the following syntax to specify the query:
+.. code-block:: php
- .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-first
- :end-before: end-first
+ SampleModel::where('', '')
+ ->skip()
+ ->get();
- .. tab:: Controller Method
- :tabid: controller
+To learn more about modifying how {+odm-long+} returns results, see the
+:ref:`laravel-read-modify-results` guide.
- To see the query results in the ``browse_movies`` view, edit the ``show()`` function
- in the ``MovieController.php`` file to resemble the following code:
+Limit Results
+-------------
- .. io-code-block::
- :copyable: true
+The following code shows how to return only a specified number of
+documents from MongoDB:
- .. input::
- :language: php
+.. code-block:: php
- class MovieController
- {
- public function show()
- {
- $movie = Movie::where('runtime', 30)
- ->orderBy('_id')
- ->first();
+ SampleModel::where('', '')
+ ->take()
+ ->get();
- return view('browse_movies', [
- 'movies' => $movie
- ]);
- }
- }
+To learn more about modifying how {+odm-long+} returns results, see the
+:ref:`laravel-read-modify-results` guide.
- .. output::
- :language: none
- :visible: false
+Sort Results
+------------
- Title: Statues also Die
- Year: 1953
- Runtime: 30
- IMDB Rating: 7.6
- IMDB Votes: 620
- Plot: A documentary of black art.
+The following code shows how to set a sort order on results returned
+from MongoDB:
-.. tip::
+.. code-block:: php
- To learn more about the ``orderBy()`` method, see the
- :ref:`laravel-sort` section of this guide.
+ SampleModel::where('field name', '')
+ ->orderBy('')
+ ->get();
-.. _laravel-read-pref:
+To learn more about modifying how {+odm-long+} returns results, see the
+:ref:`laravel-read-modify-results` guide.
Set a Read Preference
-~~~~~~~~~~~~~~~~~~~~~
+---------------------
-To specify which replica set members receive your read operations,
-set a read preference by using the ``readPreference()`` method.
+The following code shows how to set a read preference when performing a
+find operation:
-The ``readPreference()`` method accepts the following parameters:
-
-- ``mode``: *(Required)* A string value specifying the read preference
- mode.
-
-- ``tagSets``: *(Optional)* An array value specifying key-value tags that correspond to
- certain replica set members.
-
-- ``options``: *(Optional)* An array value specifying additional read preference options.
+.. code-block:: php
-.. tip::
+ SampleModel::where('field name', '')
+ ->readPreference(ReadPreference::SECONDARY_PREFERRED)
+ ->get();
- To view a full list of available read preference modes and options, see
- :php:`MongoDB\Driver\ReadPreference::__construct `
- in the MongoDB PHP extension documentation.
-
-The following example queries for documents in which the value of the ``title``
-field is ``"Carrie"`` and sets the read preference to ``ReadPreference::SECONDARY_PREFERRED``.
-As a result, the query retrieves the results from secondary replica set
-members or the primary member if no secondaries are available:
-
-.. tabs::
-
- .. tab:: Query Syntax
- :tabid: query-syntax
-
- Use the following syntax to specify the query:
-
- .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
- :language: php
- :dedent:
- :start-after: start-read-pref
- :end-before: end-read-pref
-
- .. tab:: Controller Method
- :tabid: controller
-
- To see the query results in the ``browse_movies`` view, edit the ``show()`` function
- in the ``MovieController.php`` file to resemble the following code:
-
- .. io-code-block::
- :copyable: true
-
- .. input::
- :language: php
-
- class MovieController
- {
- public function show()
- {
- $movies = Movie::where('title', 'Carrie')
- ->readPreference(ReadPreference::SECONDARY_PREFERRED)
- ->get();
-
- return view('browse_movies', [
- 'movies' => $movies
- ]);
- }
- }
-
- .. output::
- :language: none
- :visible: false
-
- Title: Carrie
- Year: 1952
- Runtime: 118
- IMDB Rating: 7.5
- IMDB Votes: 1458
- Plot: Carrie boards the train to Chicago with big ambitions. She gets a
- job stitching shoes and her sister's husband takes almost all of her pay
- for room and board. Then she injures a finger and ...
-
- Title: Carrie
- Year: 1976
- Runtime: 98
- IMDB Rating: 7.4
- IMDB Votes: 115528
- Plot: A shy, outcast 17-year old girl is humiliated by her classmates for the
- last time.
-
- Title: Carrie
- Year: 2002
- Runtime: 132
- IMDB Rating: 5.5
- IMDB Votes: 7412
- Plot: Carrie White is a lonely and painfully shy teenage girl with telekinetic
- powers who is slowly pushed to the edge of insanity by frequent bullying from
- both her classmates and her domineering, religious mother.
-
- Title: Carrie
- Year: 2013
- Runtime: 100
- IMDB Rating: 6
- IMDB Votes: 98171
- Plot: A reimagining of the classic horror tale about Carrie White, a shy girl
- outcast by her peers and sheltered by her deeply religious mother, who unleashes
- telekinetic terror on her small town after being pushed too far at her senior prom.
+To learn more about read preferences, see the :ref:`laravel-read-pref`
+guide.
diff --git a/docs/fundamentals/read-operations/modify-results.txt b/docs/fundamentals/read-operations/modify-results.txt
new file mode 100644
index 000000000..fd67422ae
--- /dev/null
+++ b/docs/fundamentals/read-operations/modify-results.txt
@@ -0,0 +1,227 @@
+.. _laravel-modify-find:
+.. _laravel-read-modify-results:
+
+====================
+Modify Query Results
+====================
+
+.. facet::
+ :name: genre
+ :values: reference
+
+.. meta::
+ :keywords: filter, criteria, CRUD, code example
+
+.. contents:: On this page
+ :local:
+ :backlinks: none
+ :depth: 2
+ :class: singlecol
+
+Overview
+--------
+
+In this guide, you can learn how to customize the way that {+odm-long+}
+returns results from queries. You can modify the results of a find
+operation by chaining more methods to the ``where()`` method.
+
+The following sections demonstrate how to modify the behavior of the
+``where()`` method:
+
+- :ref:`laravel-skip-limit` uses the ``skip()`` method to set the number of documents
+ to skip and the ``take()`` method to set the total number of documents to return
+- :ref:`laravel-sort` uses the ``orderBy()`` method to return query
+ results in a specified order based on field values
+
+To learn more about Eloquent models in the {+odm-short+}, see the
+:ref:`laravel-eloquent-models` section.
+
+.. include:: /includes/fundamentals/read-operations/before-you-get-started.rst
+
+.. _laravel-skip-limit:
+
+Skip and Limit Results
+----------------------
+
+This example queries for documents in which the ``year`` value is ``1999``.
+The operation skips the first ``2`` matching documents and outputs a total of ``3``
+documents.
+
+.. tabs::
+
+ .. tab:: Query Syntax
+ :tabid: query-syntax
+
+ Use the following syntax to specify the query:
+
+ .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-skip-limit
+ :end-before: end-skip-limit
+
+ .. tab:: Controller Method
+ :tabid: controller
+
+ To see the query results in the ``browse_movies`` view, edit the ``show()`` function
+ in the ``MovieController.php`` file to resemble the following code:
+
+ .. io-code-block::
+ :copyable: true
+
+ .. input::
+ :language: php
+
+ class MovieController
+ {
+ public function show()
+ {
+ $movies = Movie::where('year', 1999)
+ ->skip(2)
+ ->take(3)
+ ->get();
+
+ return view('browse_movies', [
+ 'movies' => $movies
+ ]);
+ }
+ }
+
+ .. output::
+ :language: none
+ :visible: false
+
+ Title: Three Kings
+ Year: 1999
+ Runtime: 114
+ IMDB Rating: 7.2
+ IMDB Votes: 130677
+ Plot: In the aftermath of the Persian Gulf War, 4 soldiers set out to steal gold
+ that was stolen from Kuwait, but they discover people who desperately need their help.
+
+ Title: Toy Story 2
+ Year: 1999
+ Runtime: 92
+ IMDB Rating: 7.9
+ IMDB Votes: 346655
+ Plot: When Woody is stolen by a toy collector, Buzz and his friends vow to rescue him,
+ but Woody finds the idea of immortality in a museum tempting.
+
+ Title: Beowulf
+ Year: 1999
+ Runtime: 95
+ IMDB Rating: 4
+ IMDB Votes: 9296
+ Plot: A sci-fi update of the famous 6th Century poem. In a besieged land, Beowulf must
+ battle against the hideous creature Grendel and his vengeance seeking mother.
+
+.. _laravel-sort:
+
+Sort Query Results
+------------------
+
+To order query results based on the values of specified fields, use the ``where()`` method
+followed by the ``orderBy()`` method.
+
+You can set an **ascending** or **descending** sort direction on
+results. By default, the ``orderBy()`` method sets an ascending sort on
+the supplied field name, but you can explicitly specify an ascending
+sort by passing ``"asc"`` as the second parameter. To
+specify a descending sort, pass ``"desc"`` as the second parameter.
+
+If your documents contain duplicate values in a specific field, you can
+handle the tie by specifying more fields to sort on. This ensures consistent
+results if the other fields contain unique values.
+
+This example queries for documents in which the value of the ``countries`` field contains
+``"Indonesia"`` and orders results first by an ascending sort on the
+``year`` field, then a descending sort on the ``title`` field.
+
+.. tabs::
+
+ .. tab:: Query Syntax
+ :tabid: query-syntax
+
+ Use the following syntax to specify the query:
+
+ .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-sort
+ :end-before: end-sort
+
+ .. tab:: Controller Method
+ :tabid: controller
+
+ To see the query results in the ``browse_movies`` view, edit the ``show()`` function
+ in the ``MovieController.php`` file to resemble the following code:
+
+ .. io-code-block::
+ :copyable: true
+
+ .. input::
+ :language: php
+
+ class MovieController
+ {
+ public function show()
+ {
+ $movies = Movie::where('countries', 'Indonesia')
+ ->orderBy('year')
+ ->orderBy('title', 'desc')
+ ->get();
+
+ return view('browse_movies', [
+ 'movies' => $movies
+ ]);
+ }
+ }
+
+ .. output::
+ :language: none
+ :visible: false
+
+ Title: Joni's Promise
+ Year: 2005
+ Runtime: 83
+ IMDB Rating: 7.6
+ IMDB Votes: 702
+ Plot: A film delivery man promises ...
+
+ Title: Gie
+ Year: 2005
+ Runtime: 147
+ IMDB Rating: 7.5
+ IMDB Votes: 470
+ Plot: Soe Hok Gie is an activist who lived in the sixties ...
+
+ Title: Requiem from Java
+ Year: 2006
+ Runtime: 120
+ IMDB Rating: 6.6
+ IMDB Votes: 316
+ Plot: Setyo (Martinus Miroto) and Siti (Artika Sari Dewi)
+ are young married couple ...
+
+ ...
+
+.. tip::
+
+ To learn more about sorting, see the following resources:
+
+ - :manual:`Natural order `
+ in the {+server-docs-name+} glossary
+ - `Ordering, Grouping, Limit, and Offset `__
+ in the Laravel documentation
+
+Additional Information
+----------------------
+
+To view runnable code examples that demonstrate how to perform find
+operations by using the {+odm-short+}, see the following usage examples:
+
+- :ref:`laravel-find-one-usage`
+- :ref:`laravel-find-usage`
+
+To learn how to retrieve data based on filter criteria, see the
+:ref:`laravel-fundamentals-read-retrieve` guide.
diff --git a/docs/fundamentals/read-operations/read-pref.txt b/docs/fundamentals/read-operations/read-pref.txt
new file mode 100644
index 000000000..075c74380
--- /dev/null
+++ b/docs/fundamentals/read-operations/read-pref.txt
@@ -0,0 +1,141 @@
+.. _laravel-read-pref:
+
+=====================
+Set a Read Preference
+=====================
+
+.. facet::
+ :name: genre
+ :values: reference
+
+.. meta::
+ :keywords: consistency, durability, CRUD, code example
+
+.. contents:: On this page
+ :local:
+ :backlinks: none
+ :depth: 2
+ :class: singlecol
+
+Overview
+--------
+
+In this guide, you can learn how to set a read preference when
+performing find operations with {+odm-long+}.
+
+.. include:: /includes/fundamentals/read-operations/before-you-get-started.rst
+
+Set a Read Preference
+---------------------
+
+To specify which replica set members receive your read operations,
+set a read preference by using the ``readPreference()`` method.
+
+The ``readPreference()`` method accepts the following parameters:
+
+- ``mode``: *(Required)* A string value specifying the read preference
+ mode.
+
+- ``tagSets``: *(Optional)* An array value specifying key-value tags that correspond to
+ certain replica set members.
+
+- ``options``: *(Optional)* An array value specifying additional read preference options.
+
+.. tip::
+
+ To view a full list of available read preference modes and options, see
+ :php:`MongoDB\Driver\ReadPreference::__construct `
+ in the MongoDB PHP extension documentation.
+
+The following example queries for documents in which the value of the ``title``
+field is ``"Carrie"`` and sets the read preference to ``ReadPreference::SECONDARY_PREFERRED``.
+As a result, the query retrieves the results from secondary replica set
+members or the primary member if no secondaries are available:
+
+.. tabs::
+
+ .. tab:: Query Syntax
+ :tabid: query-syntax
+
+ Use the following syntax to specify the query:
+
+ .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-read-pref
+ :end-before: end-read-pref
+
+ .. tab:: Controller Method
+ :tabid: controller
+
+ To see the query results in the ``browse_movies`` view, edit the ``show()`` function
+ in the ``MovieController.php`` file to resemble the following code:
+
+ .. io-code-block::
+ :copyable: true
+
+ .. input::
+ :language: php
+
+ class MovieController
+ {
+ public function show()
+ {
+ $movies = Movie::where('title', 'Carrie')
+ ->readPreference(ReadPreference::SECONDARY_PREFERRED)
+ ->get();
+
+ return view('browse_movies', [
+ 'movies' => $movies
+ ]);
+ }
+ }
+
+ .. output::
+ :language: none
+ :visible: false
+
+ Title: Carrie
+ Year: 1952
+ Runtime: 118
+ IMDB Rating: 7.5
+ IMDB Votes: 1458
+ Plot: Carrie boards the train to Chicago with big ambitions. She gets a
+ job stitching shoes and her sister's husband takes almost all of her pay
+ for room and board. Then she injures a finger and ...
+
+ Title: Carrie
+ Year: 1976
+ Runtime: 98
+ IMDB Rating: 7.4
+ IMDB Votes: 115528
+ Plot: A shy, outcast 17-year old girl is humiliated by her classmates for the
+ last time.
+
+ Title: Carrie
+ Year: 2002
+ Runtime: 132
+ IMDB Rating: 5.5
+ IMDB Votes: 7412
+ Plot: Carrie White is a lonely and painfully shy teenage girl with telekinetic
+ powers who is slowly pushed to the edge of insanity by frequent bullying from
+ both her classmates and her domineering, religious mother.
+
+ Title: Carrie
+ Year: 2013
+ Runtime: 100
+ IMDB Rating: 6
+ IMDB Votes: 98171
+ Plot: A reimagining of the classic horror tale about Carrie White, a shy girl
+ outcast by her peers and sheltered by her deeply religious mother, who unleashes
+ telekinetic terror on her small town after being pushed too
+ far at her senior prom.
+
+Additional Information
+----------------------
+
+To learn how to retrieve data based on filter criteria, see the
+:ref:`laravel-fundamentals-read-retrieve` guide.
+
+To learn how to modify the way that the {+odm-short+} returns results,
+see the :ref:`laravel-read-modify-results` guide.
diff --git a/docs/fundamentals/read-operations/retrieve.txt b/docs/fundamentals/read-operations/retrieve.txt
new file mode 100644
index 000000000..a4ca31091
--- /dev/null
+++ b/docs/fundamentals/read-operations/retrieve.txt
@@ -0,0 +1,304 @@
+.. _laravel-fundamentals-retrieve-documents:
+.. _laravel-fundamentals-read-retrieve:
+
+=============
+Retrieve Data
+=============
+
+.. facet::
+ :name: genre
+ :values: reference
+
+.. meta::
+ :keywords: filter, criteria, CRUD, code example
+
+.. contents:: On this page
+ :local:
+ :backlinks: none
+ :depth: 2
+ :class: singlecol
+
+Overview
+--------
+
+In this guide, you can learn how to retrieve data from MongoDB
+collections by using {+odm-long+}. This guide describes the Eloquent
+model methods that you can use to retrieve data and provides examples
+of different types of find operations.
+
+To learn more about Eloquent models in the {+odm-short+}, see the
+:ref:`laravel-eloquent-models` section.
+
+.. include:: /includes/fundamentals/read-operations/before-you-get-started.rst
+
+.. _laravel-retrieve-matching:
+
+Retrieve Documents that Match a Query
+-------------------------------------
+
+You can use Laravel's Eloquent object-relational mapper (ORM) to create models
+that represent MongoDB collections and chain methods on them to specify
+query criteria.
+
+To retrieve documents that match a set of criteria, call the ``where()``
+method on the collection's corresponding Eloquent model, then pass a query
+filter to the method.
+
+.. tip:: Retrieve One Document
+
+ The ``where()`` method retrieves all matching documents. To retrieve
+ the first matching document, you can chain the ``first()`` method. To
+ learn more and view an example, see the :ref:`laravel-retrieve-one`
+ section of this guide.
+
+A query filter specifies field value requirements and instructs the find
+operation to return only documents that meet these requirements.
+
+You can use one of the following ``where()`` method calls to build a query:
+
+- ``where('', )`` builds a query that matches documents in
+ which the target field has the exact specified value
+
+- ``where('', '', )`` builds a query
+ that matches documents in which the target field's value meets the comparison
+ criteria
+
+To apply multiple sets of criteria to the find operation, you can chain a series
+of ``where()`` methods together.
+
+After building your query by using the ``where()`` method, chain the ``get()``
+method to retrieve the query results.
+
+This example calls two ``where()`` methods on the ``Movie`` Eloquent model to
+retrieve documents that meet the following criteria:
+
+- ``year`` field has a value of ``2010``
+- ``imdb.rating`` nested field has a value greater than ``8.5``
+
+.. tabs::
+
+ .. tab:: Query Syntax
+ :tabid: query-syntax
+
+ Use the following syntax to specify the query:
+
+ .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-query
+ :end-before: end-query
+
+ .. tab:: Controller Method
+ :tabid: controller
+
+ To see the query results in the ``browse_movies`` view, edit the ``show()`` function
+ in the ``MovieController.php`` file to resemble the following code:
+
+ .. io-code-block::
+ :copyable: true
+
+ .. input::
+ :language: php
+
+ class MovieController
+ {
+ public function show()
+ {
+ $movies = Movie::where('year', 2010)
+ ->where('imdb.rating', '>', 8.5)
+ ->get();
+
+ return view('browse_movies', [
+ 'movies' => $movies
+ ]);
+ }
+ }
+
+ .. output::
+ :language: none
+ :visible: false
+
+ Title: Inception
+ Year: 2010
+ Runtime: 148
+ IMDB Rating: 8.8
+ IMDB Votes: 1294646
+ Plot: A thief who steals corporate secrets through use of dream-sharing
+ technology is given the inverse task of planting an idea into the mind of a CEO.
+
+ Title: Senna
+ Year: 2010
+ Runtime: 106
+ IMDB Rating: 8.6
+ IMDB Votes: 41904
+ Plot: A documentary on Brazilian Formula One racing driver Ayrton Senna, who won the
+ F1 world championship three times before his death at age 34.
+
+To learn how to query by using the Laravel query builder instead of the
+Eloquent ORM, see the :ref:`laravel-query-builder` page.
+
+Match Array Field Elements
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can specify a query filter to match array field elements when
+retrieving documents. If your documents contain an array field, you can
+match documents based on if the value contains all or some specified
+array elements.
+
+You can use one of the following ``where()`` method calls to build a
+query on an array field:
+
+- ``where('', )`` builds a query that matches documents in
+ which the array field value is exactly the specified array
+
+- ``where('', 'in', )`` builds a query
+ that matches documents in which the array field value contains one or
+ more of the specified array elements
+
+After building your query by using the ``where()`` method, chain the ``get()``
+method to retrieve the query results.
+
+Select from the following :guilabel:`Exact Array Match` and
+:guilabel:`Element Match` tabs to view the query syntax for each pattern:
+
+.. tabs::
+
+ .. tab:: Exact Array Match
+ :tabid: exact-array
+
+ This example retrieves documents in which the ``countries`` array is
+ exactly ``['Indonesia', 'Canada']``:
+
+ .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-exact-array
+ :end-before: end-exact-array
+
+ .. tab:: Element Match
+ :tabid: element-match
+
+ This example retrieves documents in which the ``countries`` array
+ contains one of the values in the array ``['Canada', 'Egypt']``:
+
+ .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-elem-match
+ :end-before: end-elem-match
+
+To learn how to query array fields by using the Laravel query builder instead of the
+Eloquent ORM, see the :ref:`laravel-query-builder-elemMatch` section in
+the Query Builder guide.
+
+.. _laravel-retrieve-one:
+
+Retrieve the First Result
+-------------------------
+
+To retrieve the first document that matches a set of criteria, use the ``where()`` method
+followed by the ``first()`` method.
+
+Chain the ``orderBy()`` method to ``first()`` to get consistent results when you query on a unique
+value. If you omit the ``orderBy()`` method, MongoDB returns the matching documents according to
+the documents' natural order, or as they appear in the collection.
+
+This example queries for documents in which the value of the ``runtime`` field is
+``30`` and returns the first matching document according to the value of the ``_id``
+field.
+
+.. tabs::
+
+ .. tab:: Query Syntax
+ :tabid: query-syntax
+
+ Use the following syntax to specify the query:
+
+ .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-first
+ :end-before: end-first
+
+ .. tab:: Controller Method
+ :tabid: controller
+
+ To see the query results in the ``browse_movies`` view, edit the ``show()`` function
+ in the ``MovieController.php`` file to resemble the following code:
+
+ .. io-code-block::
+ :copyable: true
+
+ .. input::
+ :language: php
+
+ class MovieController
+ {
+ public function show()
+ {
+ $movie = Movie::where('runtime', 30)
+ ->orderBy('_id')
+ ->first();
+
+ return view('browse_movies', [
+ 'movies' => $movie
+ ]);
+ }
+ }
+
+ .. output::
+ :language: none
+ :visible: false
+
+ Title: Statues also Die
+ Year: 1953
+ Runtime: 30
+ IMDB Rating: 7.6
+ IMDB Votes: 620
+ Plot: A documentary of black art.
+
+.. tip::
+
+ To learn more about the ``orderBy()`` method, see the
+ :ref:`laravel-sort` section of the Modify Query Results guide.
+
+.. _laravel-retrieve-all:
+
+Retrieve All Documents in a Collection
+--------------------------------------
+
+You can retrieve all documents in a collection by omitting the query filter.
+To return the documents, call the ``get()`` method on an Eloquent model that
+represents your collection. Alternatively, you can use the ``get()`` method's
+alias ``all()`` to perform the same operation.
+
+Use the following syntax to run a find operation that matches all documents:
+
+.. code-block:: php
+
+ $movies = Movie::get();
+
+.. warning::
+
+ The ``movies`` collection in the Atlas sample dataset contains a large amount of data.
+ Retrieving and displaying all documents in this collection might cause your web
+ application to time out.
+
+ To avoid this issue, specify a document limit by using the ``take()`` method. For
+ more information about ``take()``, see the :ref:`laravel-modify-find`
+ section of the Modify Query Output guide.
+
+Additional Information
+----------------------
+
+To view runnable code examples that demonstrate how to perform find
+operations by using the {+odm-short+}, see the following usage examples:
+
+- :ref:`laravel-find-one-usage`
+- :ref:`laravel-find-usage`
+
+To learn how to insert data into MongoDB, see the
+:ref:`laravel-fundamentals-write-ops` guide.
+
+To learn how to modify the way that the {+odm-short+} returns results,
+see the :ref:`laravel-read-modify-results` guide.
diff --git a/docs/fundamentals/read-operations/search-text.txt b/docs/fundamentals/read-operations/search-text.txt
new file mode 100644
index 000000000..4b465e737
--- /dev/null
+++ b/docs/fundamentals/read-operations/search-text.txt
@@ -0,0 +1,157 @@
+.. _laravel-fundamentals-search-text:
+.. _laravel-retrieve-text-search:
+
+===========
+Search Text
+===========
+
+.. facet::
+ :name: genre
+ :values: reference
+
+.. meta::
+ :keywords: filter, string, CRUD, code example
+
+.. contents:: On this page
+ :local:
+ :backlinks: none
+ :depth: 2
+ :class: singlecol
+
+Overview
+--------
+
+In this guide, you can learn how to run a **text search** by using
+{+odm-long+}.
+
+You can use a text search to retrieve documents that contain a term or a
+phrase in a specified field. A term is a sequence of characters that
+excludes whitespace characters. A phrase is a sequence of terms with any
+number of whitespace characters.
+
+This guide describes the Eloquent model methods that you can use to
+search text and provides examples. To learn more about Eloquent models
+in the {+odm-short+}, see the :ref:`laravel-eloquent-models` section.
+
+.. include:: /includes/fundamentals/read-operations/before-you-get-started.rst
+
+Search Text Fields
+------------------
+
+Before you can perform a text search, you must create a :manual:`text
+index ` on
+the text-valued field. To learn more about creating
+indexes, see the :ref:`laravel-eloquent-indexes` section of the
+Schema Builder guide.
+
+You can perform a text search by using the :manual:`$text
+` operator followed
+by the ``$search`` field in your query filter that you pass to the
+``where()`` method. The ``$text`` operator performs a text search on the
+text-indexed fields. The ``$search`` field specifies the text to search for.
+
+After building your query by using the ``where()`` method, chain the ``get()``
+method to retrieve the query results.
+
+This example calls the ``where()`` method on the ``Movie`` Eloquent model to
+retrieve documents in which the ``plot`` field contains the phrase
+``"love story"``. To perform this text search, the collection must have
+a text index on the ``plot`` field.
+
+.. tabs::
+
+ .. tab:: Query Syntax
+ :tabid: query-syntax
+
+ Use the following syntax to specify the query:
+
+ .. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-text
+ :end-before: end-text
+
+ .. tab:: Controller Method
+ :tabid: controller
+
+ To see the query results in the ``browse_movies`` view, edit the ``show()`` function
+ in the ``MovieController.php`` file to resemble the following code:
+
+ .. io-code-block::
+ :copyable: true
+
+ .. input::
+ :language: php
+
+ class MovieController
+ {
+ public function show()
+ {
+ $movies = Movie::where('$text', ['$search' => '"love story"'])
+ ->get();
+
+ return view('browse_movies', [
+ 'movies' => $movies
+ ]);
+ }
+ }
+
+ .. output::
+ :language: none
+ :visible: false
+
+ Title: Cafè de Flore
+ Year: 2011
+ Runtime: 120
+ IMDB Rating: 7.4
+ IMDB Votes: 9663
+ Plot: A love story between a man and woman ...
+
+ Title: Paheli
+ Year: 2005
+ Runtime: 140
+ IMDB Rating: 6.7
+ IMDB Votes: 8909
+ Plot: A folk tale - supernatural love story about a ghost ...
+
+ Title: Por un puèado de besos
+ Year: 2014
+ Runtime: 98
+ IMDB Rating: 6.1
+ IMDB Votes: 223
+ Plot: A girl. A boy. A love story ...
+
+ ...
+
+Search Score
+------------
+
+A text search assigns a numerical :manual:`text score ` to indicate how closely
+each result matches the string in your query filter. You can sort the
+results by relevance by using the ``orderBy()`` method to sort on the
+``textScore`` metadata field. You can access this metadata by using the
+:manual:`$meta ` operator:
+
+.. literalinclude:: /includes/fundamentals/read-operations/ReadOperationsTest.php
+ :language: php
+ :dedent:
+ :start-after: start-text-relevance
+ :end-before: end-text-relevance
+ :emphasize-lines: 2
+
+.. tip::
+
+ To learn more about the ``orderBy()`` method, see the
+ :ref:`laravel-sort` section of the Modify Query Output guide.
+
+Additional Information
+----------------------
+
+To view runnable code examples that demonstrate how to perform find
+operations by using the {+odm-short+}, see the following usage examples:
+
+- :ref:`laravel-find-one-usage`
+- :ref:`laravel-find-usage`
+
+To learn how to retrieve data based on filter criteria, see the
+:ref:`laravel-fundamentals-read-retrieve` guide.
diff --git a/docs/fundamentals/write-operations.txt b/docs/fundamentals/write-operations.txt
index 0a4d8a6ca..1b2f163be 100644
--- a/docs/fundamentals/write-operations.txt
+++ b/docs/fundamentals/write-operations.txt
@@ -133,8 +133,7 @@ matching document doesn't exist:
['upsert' => true],
);
- /* Or, use the upsert() method. */
-
+ // Or, use the upsert() method.
SampleModel::upsert(
[],
'',
diff --git a/docs/includes/fundamentals/read-operations/before-you-get-started.rst b/docs/includes/fundamentals/read-operations/before-you-get-started.rst
new file mode 100644
index 000000000..9555856fc
--- /dev/null
+++ b/docs/includes/fundamentals/read-operations/before-you-get-started.rst
@@ -0,0 +1,15 @@
+Before You Get Started
+----------------------
+
+To run the code examples in this guide, complete the :ref:`Quick Start `
+tutorial. This tutorial provides instructions on setting up a MongoDB Atlas instance with
+sample data and creating the following files in your Laravel web application:
+
+- ``Movie.php`` file, which contains a ``Movie`` model to represent documents in the ``movies``
+ collection
+- ``MovieController.php`` file, which contains a ``show()`` function to run database operations
+- ``browse_movies.blade.php`` file, which contains HTML code to display the results of database
+ operations
+
+The following sections describe how to edit the files in your Laravel application to run
+the find operation code examples and view the expected output.
From 937fb27f6e1c75f1e2fd5e3b1dd11f86f5bd1081 Mon Sep 17 00:00:00 2001
From: Rea Rustagi <85902999+rustagir@users.noreply.github.com>
Date: Wed, 5 Mar 2025 09:44:34 -0500
Subject: [PATCH 3/9] DOCSP-46479: document Scout integration (#3261)
* DOCSP-46479: document Scout integration
* NR PR fixes 1
* fix spacing
* fix spacing
* fix spacing
* fix spacing
* NR PR fixes 2
* JT tech comment
* fix spacing
* JT tech review 1
* JT tech review 1
* custom index
* link to atlas doc
---
docs/index.txt | 2 +
docs/scout.txt | 259 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 261 insertions(+)
create mode 100644 docs/scout.txt
diff --git a/docs/index.txt b/docs/index.txt
index 2937968a7..1eb1d8657 100644
--- a/docs/index.txt
+++ b/docs/index.txt
@@ -22,6 +22,7 @@
Databases & Collections
User Authentication
Cache & Locks
+ Scout Integration
HTTP Sessions
Queues
Transactions
@@ -86,6 +87,7 @@ see the following content:
- :ref:`laravel-aggregation-builder`
- :ref:`laravel-user-authentication`
- :ref:`laravel-cache`
+- :ref:`laravel-scout`
- :ref:`laravel-sessions`
- :ref:`laravel-queues`
- :ref:`laravel-transactions`
diff --git a/docs/scout.txt b/docs/scout.txt
new file mode 100644
index 000000000..8f409148b
--- /dev/null
+++ b/docs/scout.txt
@@ -0,0 +1,259 @@
+.. _laravel-scout:
+
+===========================
+Full-Text Search with Scout
+===========================
+
+.. facet::
+ :name: genre
+ :values: reference
+
+.. meta::
+ :keywords: php framework, odm, code example, text search, atlas
+
+.. contents:: On this page
+ :local:
+ :backlinks: none
+ :depth: 2
+ :class: singlecol
+
+Overview
+--------
+
+In this guide, you can learn how to use the Laravel Scout feature in
+your {+odm-long+} application. Scout enables you to implement full-text
+search on your Eloquent models. To learn more, see `Laravel Scout
+`__ in the
+Laravel documentation.
+
+The Scout integration for {+odm-long+} provides the following
+functionality:
+
+- Provides an abstraction to create :atlas:`Atlas Search indexes
+ ` from any MongoDB or SQL model.
+
+ .. important:: Use Schema Builder to Create Search Indexes
+
+ If your documents are already in MongoDB, create Search indexes
+ by using {+php-library+} or ``Schema`` builder methods to improve
+ search query performance. To learn more about creating Search
+ indexes, see the :ref:`laravel-as-index` section of the Atlas
+ Search guide.
+
+- Enables you to automatically replicate data from MongoDB into a
+ search engine such as `Meilisearch `__
+ or `Algolia `__. You can use a MongoDB Eloquent
+ model as the source to import and index. To learn more about indexing
+ to a search engine, see the `Indexing
+ `__
+ section of the Laravel Scout documentation.
+
+.. important:: Deployment Compatibility
+
+ You can use Laravel Scout only when you connect to MongoDB Atlas
+ deployments. This feature is not available for self-managed
+ deployments.
+
+Scout for Atlas Search Tutorial
+-------------------------------
+
+This tutorial demonstrates how to use Scout to compound and index
+documents for MongoDB Atlas Search from Eloquent models (MongoDB or SQL).
+
+.. procedure::
+ :style: connected
+
+ .. step:: Install the Scout package
+
+ Before you can use Scout in your application, run the following
+ command from your application's root directory to install the
+ ``laravel/scout`` package:
+
+ .. code-block:: bash
+
+ composer require laravel/scout
+
+ .. step:: Add the Searchable trait to your model
+
+ Add the ``Laravel\Scout\Searchable`` trait to an Eloquent model to make
+ it searchable. The following example adds this trait to the ``Movie``
+ model, which represents documents in the ``sample_mflix.movies``
+ collection:
+
+ .. code-block:: php
+ :emphasize-lines: 6, 10
+
+ `__
+ section of the Laravel Scout documentation.
+
+ .. step:: Configure Scout in your application
+
+ Ensure that your application is configured to use MongoDB as its
+ database connection. To learn how to configure MongoDB, see the
+ :ref:`laravel-quick-start-connect-to-mongodb` section of the Quick Start
+ guide.
+
+ To configure Scout in your application, create a file named
+ ``scout.php`` in your application's ``config`` directory. Paste the
+ following code into the file to configure Scout:
+
+ .. code-block:: php
+ :caption: config/scout.php
+
+ env('SCOUT_DRIVER', 'mongodb'),
+ 'mongodb' => [
+ 'connection' => env('SCOUT_MONGODB_CONNECTION', 'mongodb'),
+ ],
+ 'prefix' => env('SCOUT_PREFIX', 'scout_'),
+ ];
+
+ The preceding code specifies the following configuration:
+
+ - Uses the value of the ``SCOUT_DRIVER`` environment variable as
+ the default search driver, or ``mongodb`` if the environment
+ variable is not set
+
+ - Specifies ``scout_`` as the prefix for the collection name of the
+ searchable collection
+
+ In the ``config/scout.php`` file, you can also specify a custom
+ Atlas Search index definition. To learn more, see the :ref:`custom
+ index definition example ` in the
+ following step.
+
+ Set the following environment variable in your application's
+ ``.env`` file to select ``mongodb`` as the default search driver:
+
+ .. code-block:: none
+ :caption: .env
+
+ SCOUT_DRIVER=mongodb
+
+ .. tip:: Queueing
+
+ When using Scout, consider configuring a queue driver to reduce
+ response times for your application's web interface. To learn more,
+ see the `Queuing section
+ `__
+ of the Laravel Scout documentation and the :ref:`laravel-queues` guide.
+
+ .. step:: Create the Atlas Search index
+
+ After you configure Scout and set your default search driver, you can
+ create your searchable collection and search index by running the
+ following command from your application's root directory:
+
+ .. code-block:: bash
+
+ php artisan scout:index 'App\Models\Movie'
+
+ Because you set MongoDB as the default search driver, the preceding
+ command creates the search collection with an Atlas Search index in your
+ MongoDB database. The collection is named ``scout_movies``, based on the prefix
+ set in the preceding step. The Atlas Search index is named ``scout``
+ and has the following configuration by default:
+
+ .. code-block:: json
+
+ {
+ "mappings": {
+ "dynamic": true
+ }
+ }
+
+ .. _laravel-scout-custom-index:
+
+ To customize the index definition, add the ``index-definitions``
+ configuration to the ``mongodb`` entry in your
+ ``config/scout.php`` file. The following code demonstrates how to
+ specify a custom index definition to create on the
+ ``scout_movies`` collection:
+
+ .. code-block:: php
+
+ 'mongodb' => [
+ 'connection' => env('SCOUT_MONGODB_CONNECTION', 'mongodb'),
+ 'index-definitions' => [
+ 'scout_movies' => [
+ 'mappings' => [
+ 'dynamic' => false,
+ 'fields' => ['title' => ['type' => 'string']]
+ ]
+ ]
+ ]
+ ], ...
+
+ To learn more about defining Atlas Search index definitions, see the
+ :atlas:`Define Field Mappings
+ ` guide in the Atlas
+ documentation.
+
+ .. note::
+
+ MongoDB can take up to a minute to create and finalize
+ an Atlas Search index, so the ``scout:index`` command might not
+ return a success message immediately.
+
+ .. step:: Import data into the searchable collection
+
+ You can use Scout to replicate data from a source collection
+ modeled by your Eloquent model into a searchable collection. The
+ following command replicates and indexes data from the ``movies``
+ collection into the ``scout_movies`` collection indexed in the
+ preceding step:
+
+ .. code-block:: bash
+
+ php artisan scout:import 'App\Models\Movie'
+
+ The documents are automatically indexed for Atlas Search queries.
+
+ .. tip:: Select Fields to Import
+
+ You might not need all the fields from your source documents in your
+ searchable collection. Limiting the amount of data you replicate can improve
+ your application's speed and performance.
+
+ You can select specific fields to import by defining the
+ ``toSearchableArray()`` method in your Eloquent model class. The
+ following code demonstrates how to define ``toSearchableArray()`` to
+ select only the ``plot`` and ``title`` fields for replication:
+
+ .. code-block:: php
+
+ class Movie extends Model
+ {
+ ....
+ public function toSearchableArray(): array
+ {
+ return [
+ 'plot' => $this->plot,
+ 'title' => $this->title,
+ ];
+ }
+ }
+
+After completing these steps, you can perform Atlas Search queries on the
+``scout_movies`` collection in your {+odm-long+} application. To learn
+how to perform full-text searches, see the :ref:`laravel-atlas-search`
+guide.
From 536327d0ef77d5fc3d8e421f5e8dd35e972daa45 Mon Sep 17 00:00:00 2001
From: Rea Rustagi <85902999+rustagir@users.noreply.github.com>
Date: Wed, 5 Mar 2025 11:09:19 -0500
Subject: [PATCH 4/9] DOCSP-48018: laravel 12 feature compat (#3304)
* DOCSP-48018: laravel 12 feature compat
* small fixes
* JT fix
---
docs/eloquent-models/model-class.txt | 7 ++++---
docs/feature-compatibility.txt | 19 +++++++++++++------
2 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/docs/eloquent-models/model-class.txt b/docs/eloquent-models/model-class.txt
index a2a9861bc..6f686e88a 100644
--- a/docs/eloquent-models/model-class.txt
+++ b/docs/eloquent-models/model-class.txt
@@ -200,9 +200,10 @@ model attribute, stored in MongoDB as a :php:`MongoDB\\BSON\\UTCDateTime
.. tip:: Casts in Laravel 11
- In Laravel 11, you can define a ``casts()`` method to specify data type conversions
- instead of using the ``$casts`` attribute. The following code performs the same
- conversion as the preceding example by using a ``casts()`` method:
+ Starting in Laravel 11, you can define a ``casts()`` method to
+ specify data type conversions instead of using the ``$casts``
+ attribute. The following code performs the same conversion as the
+ preceding example by using a ``casts()`` method:
.. code-block:: php
diff --git a/docs/feature-compatibility.txt b/docs/feature-compatibility.txt
index 57c8c7486..965be2ebb 100644
--- a/docs/feature-compatibility.txt
+++ b/docs/feature-compatibility.txt
@@ -21,7 +21,7 @@ Overview
--------
This guide describes the Laravel features that are supported by
-{+odm-long+}. This page discusses Laravel version 11.x feature
+{+odm-long+}. This page discusses Laravel version 12.x feature
availability in the {+odm-short+}.
The following sections contain tables that describe whether individual
@@ -32,6 +32,7 @@ Database Features
.. list-table::
:header-rows: 1
+ :widths: 40 60
* - Eloquent Feature
- Availability
@@ -63,6 +64,12 @@ Database Features
* - Database Monitoring
- *Unsupported*
+ * - Multi-database Support / Multiple Schemas
+ - *Unsupported* Laravel uses a dot separator (``.``)
+ between SQL schema and table names, but MongoDB allows ``.``
+ characters within collection names, which might lead to
+ unexpected namespace parsing.
+
Query Features
--------------
@@ -114,19 +121,19 @@ The following Eloquent methods are not supported in the {+odm-short+}:
* - Unions
- *Unsupported*
- * - `Basic Where Clauses `__
+ * - `Basic Where Clauses `__
- ✓
- * - `Additional Where Clauses `__
+ * - `Additional Where Clauses `__
- ✓
* - Logical Grouping
- ✓
- * - `Advanced Where Clauses `__
+ * - `Advanced Where Clauses `__
- ✓
- * - `Subquery Where Clauses `__
+ * - `Subquery Where Clauses `__
- *Unsupported*
* - Ordering
@@ -136,7 +143,7 @@ The following Eloquent methods are not supported in the {+odm-short+}:
- *Unsupported*
* - Grouping
- - Partially supported, use :ref:`Aggregations `.
+ - Partially supported. Use :ref:`Aggregations `.
* - Limit and Offset
- ✓
From 89772e239af7d9d3f51d29816ace06a34ca260ef Mon Sep 17 00:00:00 2001
From: Nora Reidy
Date: Thu, 6 Mar 2025 10:38:47 -0500
Subject: [PATCH 5/9] DOCSP-47950: Fix all operator section (#3308)
* DOCSP-47950: Fix all operator section
* review feedback
---
docs/includes/query-builder/QueryBuilderTest.php | 2 +-
docs/query-builder.txt | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/docs/includes/query-builder/QueryBuilderTest.php b/docs/includes/query-builder/QueryBuilderTest.php
index 574fe060f..3f7ea2274 100644
--- a/docs/includes/query-builder/QueryBuilderTest.php
+++ b/docs/includes/query-builder/QueryBuilderTest.php
@@ -351,7 +351,7 @@ public function testAll(): void
{
// begin query all
$result = DB::table('movies')
- ->where('movies', 'all', ['title', 'rated', 'imdb.rating'])
+ ->where('writers', 'all', ['Ben Affleck', 'Matt Damon'])
->get();
// end query all
diff --git a/docs/query-builder.txt b/docs/query-builder.txt
index c641323dc..68a9b2102 100644
--- a/docs/query-builder.txt
+++ b/docs/query-builder.txt
@@ -869,7 +869,8 @@ Contains All Fields Example
The following example shows how to use the ``all`` query
operator with the ``where()`` query builder method to match
-documents that contain all the specified fields:
+documents that have a ``writers`` array field containing all
+the specified values:
.. literalinclude:: /includes/query-builder/QueryBuilderTest.php
:language: php
From 4fd1b811d1b20eeaafde32f02c2501bf84b59d63 Mon Sep 17 00:00:00 2001
From: Rea Rustagi <85902999+rustagir@users.noreply.github.com>
Date: Thu, 6 Mar 2025 16:17:17 -0500
Subject: [PATCH 6/9] Remove link to builder package/repo (#3312)
---
docs/fundamentals/aggregation-builder.txt | 6 ------
1 file changed, 6 deletions(-)
diff --git a/docs/fundamentals/aggregation-builder.txt b/docs/fundamentals/aggregation-builder.txt
index 9ae31f0c1..47994ce9e 100644
--- a/docs/fundamentals/aggregation-builder.txt
+++ b/docs/fundamentals/aggregation-builder.txt
@@ -66,12 +66,6 @@ to build aggregation stages:
- ``MongoDB\Builder\Query``
- ``MongoDB\Builder\Type``
-.. tip::
-
- To learn more about builder classes, see the
- :github:`mongodb/mongodb-php-builder `
- GitHub repository.
-
This section features the following examples that show how to use common
aggregation stages:
From b91a3c5f9afc49e54426e834256e91249feaeb8d Mon Sep 17 00:00:00 2001
From: Rea Rustagi <85902999+rustagir@users.noreply.github.com>
Date: Tue, 11 Mar 2025 09:35:38 -0400
Subject: [PATCH 7/9] fix line spacing in feature compat doc (#3315)
---
docs/feature-compatibility.txt | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/docs/feature-compatibility.txt b/docs/feature-compatibility.txt
index 965be2ebb..c36d30812 100644
--- a/docs/feature-compatibility.txt
+++ b/docs/feature-compatibility.txt
@@ -65,10 +65,11 @@ Database Features
- *Unsupported*
* - Multi-database Support / Multiple Schemas
- - *Unsupported* Laravel uses a dot separator (``.``)
- between SQL schema and table names, but MongoDB allows ``.``
- characters within collection names, which might lead to
- unexpected namespace parsing.
+ - | *Unsupported*
+ | Laravel uses a dot separator (``.``)
+ between SQL schema and table names, but MongoDB allows ``.``
+ characters within collection names, which might lead to
+ unexpected namespace parsing.
Query Features
--------------
From 1265bb1e9d5904e585822eb79e2d4d98c8254ed7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
Date: Mon, 31 Mar 2025 10:39:05 +0200
Subject: [PATCH 8/9] PHPORM-306 Test with MongoDB Driver v2 (#3319)
---
.github/workflows/build-ci-atlas.yml | 23 ++-
.github/workflows/build-ci.yml | 25 ++-
.github/workflows/coding-standards.yml | 2 +-
.github/workflows/static-analysis.yml | 17 +-
composer.json | 4 +-
src/Eloquent/Builder.php | 4 +-
tests/QueryBuilderTest.php | 6 +-
tests/Scout/ScoutEngineTest.php | 230 +++++++++++++------------
8 files changed, 189 insertions(+), 122 deletions(-)
diff --git a/.github/workflows/build-ci-atlas.yml b/.github/workflows/build-ci-atlas.yml
index 30b4b06b1..339f8fc38 100644
--- a/.github/workflows/build-ci-atlas.yml
+++ b/.github/workflows/build-ci-atlas.yml
@@ -4,11 +4,15 @@ on:
push:
pull_request:
+env:
+ MONGODB_EXT_V1: mongodb-1.21.0
+ MONGODB_EXT_V2: mongodb-mongodb/mongo-php-driver@v2.x
+
jobs:
build:
runs-on: "${{ matrix.os }}"
- name: "PHP ${{ matrix.php }} Laravel ${{ matrix.laravel }} Atlas"
+ name: "PHP/${{ matrix.php }} Laravel/${{ matrix.laravel }} Driver/${{ matrix.driver }}"
strategy:
matrix:
@@ -21,6 +25,13 @@ jobs:
laravel:
- "11.*"
- "12.*"
+ driver:
+ - 1
+ include:
+ - php: "8.4"
+ laravel: "12.*"
+ os: "ubuntu-latest"
+ driver: 2
steps:
- uses: "actions/checkout@v4"
@@ -39,11 +50,19 @@ jobs:
run: |
docker exec --tty mongodb mongosh --eval "db.runCommand({ serverStatus: 1 })"
+ - name: Setup cache environment
+ id: extcache
+ uses: shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: ${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
+ key: "extcache-v1"
+
- name: "Installing php"
uses: "shivammathur/setup-php@v2"
with:
php-version: ${{ matrix.php }}
- extensions: "curl,mbstring,xdebug"
+ extensions: "curl,mbstring,xdebug,${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}"
coverage: "xdebug"
tools: "composer"
diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml
index 659c316d3..bc799c70e 100644
--- a/.github/workflows/build-ci.yml
+++ b/.github/workflows/build-ci.yml
@@ -4,11 +4,15 @@ on:
push:
pull_request:
+env:
+ MONGODB_EXT_V1: mongodb-1.21.0
+ MONGODB_EXT_V2: mongodb-mongodb/mongo-php-driver@v2.x
+
jobs:
build:
runs-on: "${{ matrix.os }}"
- name: "PHP ${{ matrix.php }} Laravel ${{ matrix.laravel }} MongoDB ${{ matrix.mongodb }} ${{ matrix.mode }}"
+ name: "PHP/${{ matrix.php }} Laravel/${{ matrix.laravel }} Driver/${{ matrix.driver }} Server/${{ matrix.mongodb }} ${{ matrix.mode }}"
strategy:
matrix:
@@ -29,12 +33,21 @@ jobs:
- "10.*"
- "11.*"
- "12.*"
+ driver:
+ - 1
include:
- php: "8.1"
laravel: "10.*"
mongodb: "5.0"
mode: "low-deps"
os: "ubuntu-latest"
+ driver: 1.x
+ driver_version: "1.21.0"
+ - php: "8.4"
+ laravel: "12.*"
+ mongodb: "8.0"
+ os: "ubuntu-latest"
+ driver: 2
exclude:
- php: "8.1"
laravel: "11.*"
@@ -59,11 +72,19 @@ jobs:
if [ "${{ matrix.mongodb }}" = "4.4" ]; then MONGOSH_BIN="mongo"; else MONGOSH_BIN="mongosh"; fi
docker exec --tty mongodb $MONGOSH_BIN --eval "db.runCommand({ serverStatus: 1 })"
+ - name: Setup cache environment
+ id: extcache
+ uses: shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: ${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
+ key: "extcache-v1"
+
- name: "Installing php"
uses: "shivammathur/setup-php@v2"
with:
php-version: ${{ matrix.php }}
- extensions: "curl,mbstring,xdebug"
+ extensions: "curl,mbstring,xdebug,${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}"
coverage: "xdebug"
tools: "composer"
diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index 24d397294..946e84971 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -5,7 +5,7 @@ on:
pull_request:
env:
- PHP_VERSION: "8.2"
+ PHP_VERSION: "8.4"
DRIVER_VERSION: "stable"
jobs:
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index a66100d93..e0c907953 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -13,9 +13,12 @@ on:
env:
PHP_VERSION: "8.2"
DRIVER_VERSION: "stable"
+ MONGODB_EXT_V1: mongodb-1.21.0
+ MONGODB_EXT_V2: mongodb-mongodb/mongo-php-driver@v2.x
jobs:
phpstan:
+ name: "PHP/${{ matrix.php }} Driver/${{ matrix.driver }}"
runs-on: "ubuntu-22.04"
continue-on-error: true
strategy:
@@ -24,6 +27,10 @@ jobs:
- '8.1'
- '8.2'
- '8.3'
+ - '8.4'
+ driver:
+ - 1
+ - 2
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -35,11 +42,19 @@ jobs:
run: |
echo CHECKED_OUT_SHA=$(git rev-parse HEAD) >> $GITHUB_ENV
+ - name: Setup cache environment
+ id: extcache
+ uses: shivammathur/cache-extensions@v1
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: ${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}
+ key: "extcache-v1"
+
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
- extensions: curl, mbstring
+ extensions: "curl,mbstring,${{ matrix.driver == 1 && env.MONGODB_EXT_V1 || env.MONGODB_EXT_V2 }}"
tools: composer:v2
coverage: none
diff --git a/composer.json b/composer.json
index a6f5470aa..2542b51bb 100644
--- a/composer.json
+++ b/composer.json
@@ -23,14 +23,14 @@
"license": "MIT",
"require": {
"php": "^8.1",
- "ext-mongodb": "^1.21",
+ "ext-mongodb": "^1.21|^2",
"composer-runtime-api": "^2.0.0",
"illuminate/cache": "^10.36|^11|^12",
"illuminate/container": "^10.0|^11|^12",
"illuminate/database": "^10.30|^11|^12",
"illuminate/events": "^10.0|^11|^12",
"illuminate/support": "^10.0|^11|^12",
- "mongodb/mongodb": "^1.21",
+ "mongodb/mongodb": "^1.21|^2",
"symfony/http-foundation": "^6.4|^7"
},
"require-dev": {
diff --git a/src/Eloquent/Builder.php b/src/Eloquent/Builder.php
index eedbe8712..f85570575 100644
--- a/src/Eloquent/Builder.php
+++ b/src/Eloquent/Builder.php
@@ -11,7 +11,7 @@
use MongoDB\Builder\Type\QueryInterface;
use MongoDB\Builder\Type\SearchOperatorInterface;
use MongoDB\Driver\CursorInterface;
-use MongoDB\Driver\Exception\WriteException;
+use MongoDB\Driver\Exception\BulkWriteException;
use MongoDB\Laravel\Connection;
use MongoDB\Laravel\Helpers\QueriesRelationships;
use MongoDB\Laravel\Query\AggregationBuilder;
@@ -285,7 +285,7 @@ public function createOrFirst(array $attributes = [], array $values = [])
try {
return $this->create(array_merge($attributes, $values));
- } catch (WriteException $e) {
+ } catch (BulkWriteException $e) {
if ($e->getCode() === self::DUPLICATE_KEY_ERROR) {
return $this->where($attributes)->first() ?? throw $e;
}
diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php
index 9592bbe7c..46beebab1 100644
--- a/tests/QueryBuilderTest.php
+++ b/tests/QueryBuilderTest.php
@@ -161,7 +161,7 @@ public function testFindWithTimeout()
$id = DB::table('users')->insertGetId(['name' => 'John Doe']);
$subscriber = new class implements CommandSubscriber {
- public function commandStarted(CommandStartedEvent $event)
+ public function commandStarted(CommandStartedEvent $event): void
{
if ($event->getCommandName() !== 'find') {
return;
@@ -171,11 +171,11 @@ public function commandStarted(CommandStartedEvent $event)
Assert::assertSame(1000, $event->getCommand()->maxTimeMS);
}
- public function commandFailed(CommandFailedEvent $event)
+ public function commandFailed(CommandFailedEvent $event): void
{
}
- public function commandSucceeded(CommandSucceededEvent $event)
+ public function commandSucceeded(CommandSucceededEvent $event): void
{
}
};
diff --git a/tests/Scout/ScoutEngineTest.php b/tests/Scout/ScoutEngineTest.php
index 40d943ffb..7b254ec9c 100644
--- a/tests/Scout/ScoutEngineTest.php
+++ b/tests/Scout/ScoutEngineTest.php
@@ -11,13 +11,11 @@
use Laravel\Scout\Builder;
use Laravel\Scout\Jobs\RemoveFromSearch;
use LogicException;
-use Mockery as m;
use MongoDB\BSON\Document;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Collection;
use MongoDB\Database;
use MongoDB\Driver\CursorInterface;
-use MongoDB\Laravel\Eloquent\Model;
use MongoDB\Laravel\Scout\ScoutEngine;
use MongoDB\Laravel\Tests\Scout\Models\ScoutUser;
use MongoDB\Laravel\Tests\Scout\Models\SearchableModel;
@@ -36,7 +34,7 @@ class ScoutEngineTest extends TestCase
public function testCreateIndexInvalidDefinition(): void
{
- $database = m::mock(Database::class);
+ $database = $this->createMock(Database::class);
$engine = new ScoutEngine($database, false, ['collection_invalid' => ['foo' => 'bar']]);
$this->expectException(LogicException::class);
@@ -53,21 +51,22 @@ public function testCreateIndex(): void
],
];
- $database = m::mock(Database::class);
- $collection = m::mock(Collection::class);
- $database->shouldReceive('createCollection')
- ->once()
+ $database = $this->createMock(Database::class);
+ $collection = $this->createMock(Collection::class);
+ $database->expects($this->once())
+ ->method('createCollection')
->with($collectionName);
- $database->shouldReceive('selectCollection')
+ $database->expects($this->once())
+ ->method('selectCollection')
->with($collectionName)
- ->andReturn($collection);
- $collection->shouldReceive('createSearchIndex')
- ->once()
+ ->willReturn($collection);
+ $collection->expects($this->once())
+ ->method('createSearchIndex')
->with($expectedDefinition, ['name' => 'scout']);
- $collection->shouldReceive('listSearchIndexes')
- ->once()
+ $collection->expects($this->once())
+ ->method('listSearchIndexes')
->with(['name' => 'scout', 'typeMap' => ['root' => 'bson']])
- ->andReturn(new ArrayIterator([Document::fromPHP(['name' => 'scout', 'status' => 'READY'])]));
+ ->willReturn(new ArrayIterator([Document::fromPHP(['name' => 'scout', 'status' => 'READY'])]));
$engine = new ScoutEngine($database, false, []);
$engine->createIndex($collectionName);
@@ -90,21 +89,22 @@ public function testCreateIndexCustomDefinition(): void
],
];
- $database = m::mock(Database::class);
- $collection = m::mock(Collection::class);
- $database->shouldReceive('createCollection')
- ->once()
+ $database = $this->createMock(Database::class);
+ $collection = $this->createMock(Collection::class);
+ $database->expects($this->once())
+ ->method('createCollection')
->with($collectionName);
- $database->shouldReceive('selectCollection')
+ $database->expects($this->once())
+ ->method('selectCollection')
->with($collectionName)
- ->andReturn($collection);
- $collection->shouldReceive('createSearchIndex')
- ->once()
+ ->willReturn($collection);
+ $collection->expects($this->once())
+ ->method('createSearchIndex')
->with($expectedDefinition, ['name' => 'scout']);
- $collection->shouldReceive('listSearchIndexes')
- ->once()
+ $collection->expects($this->once())
+ ->method('listSearchIndexes')
->with(['name' => 'scout', 'typeMap' => ['root' => 'bson']])
- ->andReturn(new ArrayIterator([Document::fromPHP(['name' => 'scout', 'status' => 'READY'])]));
+ ->willReturn(new ArrayIterator([Document::fromPHP(['name' => 'scout', 'status' => 'READY'])]));
$engine = new ScoutEngine($database, false, [$collectionName => $expectedDefinition]);
$engine->createIndex($collectionName);
@@ -115,26 +115,28 @@ public function testCreateIndexCustomDefinition(): void
public function testSearch(Closure $builder, array $expectedPipeline): void
{
$data = [['_id' => 'key_1', '__count' => 15], ['_id' => 'key_2', '__count' => 15]];
- $database = m::mock(Database::class);
- $collection = m::mock(Collection::class);
- $database->shouldReceive('selectCollection')
+ $database = $this->createMock(Database::class);
+ $collection = $this->createMock(Collection::class);
+ $database->expects($this->once())
+ ->method('selectCollection')
->with('collection_searchable')
- ->andReturn($collection);
- $cursor = m::mock(CursorInterface::class);
- $cursor->shouldReceive('setTypeMap')->once()->with(self::EXPECTED_TYPEMAP);
- $cursor->shouldReceive('toArray')->once()->with()->andReturn($data);
-
- $collection->shouldReceive('getCollectionName')
- ->zeroOrMoreTimes()
- ->andReturn('collection_searchable');
- $collection->shouldReceive('aggregate')
- ->once()
- ->withArgs(function ($pipeline) use ($expectedPipeline) {
- self::assertEquals($expectedPipeline, $pipeline);
-
- return true;
- })
- ->andReturn($cursor);
+ ->willReturn($collection);
+ $cursor = $this->createMock(CursorInterface::class);
+ $cursor->expects($this->once())
+ ->method('setTypeMap')
+ ->with(self::EXPECTED_TYPEMAP);
+ $cursor->expects($this->once())
+ ->method('toArray')
+ ->with()
+ ->willReturn($data);
+
+ $collection->expects($this->any())
+ ->method('getCollectionName')
+ ->willReturn('collection_searchable');
+ $collection->expects($this->once())
+ ->method('aggregate')
+ ->with($expectedPipeline)
+ ->willReturn($cursor);
$engine = new ScoutEngine($database, softDelete: false);
$result = $engine->search($builder());
@@ -414,15 +416,15 @@ public function testPaginate()
$perPage = 5;
$page = 3;
- $database = m::mock(Database::class);
- $collection = m::mock(Collection::class);
- $cursor = m::mock(CursorInterface::class);
- $database->shouldReceive('selectCollection')
+ $database = $this->createMock(Database::class);
+ $collection = $this->createMock(Collection::class);
+ $cursor = $this->createMock(CursorInterface::class);
+ $database->method('selectCollection')
->with('collection_searchable')
- ->andReturn($collection);
- $collection->shouldReceive('aggregate')
- ->once()
- ->withArgs(function (...$args) {
+ ->willReturn($collection);
+ $collection->expects($this->once())
+ ->method('aggregate')
+ ->willReturnCallback(function (...$args) use ($cursor) {
self::assertSame([
[
'$search' => [
@@ -468,14 +470,11 @@ public function testPaginate()
],
], $args[0]);
- return true;
- })
- ->andReturn($cursor);
- $cursor->shouldReceive('setTypeMap')->once()->with(self::EXPECTED_TYPEMAP);
- $cursor->shouldReceive('toArray')
- ->once()
- ->with()
- ->andReturn([['_id' => 'key_1', '__count' => 17], ['_id' => 'key_2', '__count' => 17]]);
+ return $cursor;
+ });
+ $cursor->expects($this->once())->method('setTypeMap')->with(self::EXPECTED_TYPEMAP);
+ $cursor->expects($this->once())->method('toArray')->with()
+ ->willReturn([['_id' => 'key_1', '__count' => 17], ['_id' => 'key_2', '__count' => 17]]);
$engine = new ScoutEngine($database, softDelete: false);
$builder = new Builder(new SearchableModel(), 'mustang');
@@ -485,20 +484,27 @@ public function testPaginate()
public function testMapMethodRespectsOrder()
{
- $database = m::mock(Database::class);
+ $database = $this->createMock(Database::class);
+ $query = $this->createMock(Builder::class);
$engine = new ScoutEngine($database, false);
- $model = m::mock(Model::class);
- $model->shouldReceive(['getScoutKeyName' => 'id']);
- $model->shouldReceive('queryScoutModelsByIds->get')
- ->andReturn(LaravelCollection::make([
+ $model = $this->createMock(SearchableModel::class);
+ $model->expects($this->any())
+ ->method('getScoutKeyName')
+ ->willReturn('id');
+ $model->expects($this->once())
+ ->method('queryScoutModelsByIds')
+ ->willReturn($query);
+ $query->expects($this->once())
+ ->method('get')
+ ->willReturn(LaravelCollection::make([
new ScoutUser(['id' => 1]),
new ScoutUser(['id' => 2]),
new ScoutUser(['id' => 3]),
new ScoutUser(['id' => 4]),
]));
- $builder = m::mock(Builder::class);
+ $builder = $this->createMock(Builder::class);
$results = $engine->map($builder, [
['_id' => 1, '__count' => 4],
@@ -518,21 +524,27 @@ public function testMapMethodRespectsOrder()
public function testLazyMapMethodRespectsOrder()
{
- $lazy = false;
- $database = m::mock(Database::class);
+ $database = $this->createMock(Database::class);
+ $query = $this->createMock(Builder::class);
$engine = new ScoutEngine($database, false);
- $model = m::mock(Model::class);
- $model->shouldReceive(['getScoutKeyName' => 'id']);
- $model->shouldReceive('queryScoutModelsByIds->cursor')
- ->andReturn(LazyCollection::make([
+ $model = $this->createMock(SearchableModel::class);
+ $model->expects($this->any())
+ ->method('getScoutKeyName')
+ ->willReturn('id');
+ $model->expects($this->once())
+ ->method('queryScoutModelsByIds')
+ ->willReturn($query);
+ $query->expects($this->once())
+ ->method('cursor')
+ ->willReturn(LazyCollection::make([
new ScoutUser(['id' => 1]),
new ScoutUser(['id' => 2]),
new ScoutUser(['id' => 3]),
new ScoutUser(['id' => 4]),
]));
- $builder = m::mock(Builder::class);
+ $builder = $this->createMock(Builder::class);
$results = $engine->lazyMap($builder, [
['_id' => 1, '__count' => 4],
@@ -553,13 +565,14 @@ public function testLazyMapMethodRespectsOrder()
public function testUpdate(): void
{
$date = new DateTimeImmutable('2000-01-02 03:04:05');
- $database = m::mock(Database::class);
- $collection = m::mock(Collection::class);
- $database->shouldReceive('selectCollection')
+ $database = $this->createMock(Database::class);
+ $collection = $this->createMock(Collection::class);
+ $database->expects($this->once())
+ ->method('selectCollection')
->with('collection_indexable')
- ->andReturn($collection);
- $collection->shouldReceive('bulkWrite')
- ->once()
+ ->willReturn($collection);
+ $collection->expects($this->once())
+ ->method('bulkWrite')
->with([
[
'updateOne' => [
@@ -592,26 +605,23 @@ public function testUpdate(): void
public function testUpdateWithSoftDelete(): void
{
$date = new DateTimeImmutable('2000-01-02 03:04:05');
- $database = m::mock(Database::class);
- $collection = m::mock(Collection::class);
- $database->shouldReceive('selectCollection')
+ $database = $this->createMock(Database::class);
+ $collection = $this->createMock(Collection::class);
+ $database->expects($this->once())
+ ->method('selectCollection')
->with('collection_indexable')
- ->andReturn($collection);
- $collection->shouldReceive('bulkWrite')
- ->once()
- ->withArgs(function ($pipeline) {
- $this->assertSame([
- [
- 'updateOne' => [
- ['_id' => 'key_1'],
- ['$set' => ['id' => 1, '__soft_deleted' => false]],
- ['upsert' => true],
- ],
+ ->willReturn($collection);
+ $collection->expects($this->once())
+ ->method('bulkWrite')
+ ->with([
+ [
+ 'updateOne' => [
+ ['_id' => 'key_1'],
+ ['$set' => ['id' => 1, '__soft_deleted' => false]],
+ ['upsert' => true],
],
- ], $pipeline);
-
- return true;
- });
+ ],
+ ]);
$model = new SearchableModel(['id' => 1]);
$model->delete();
@@ -622,13 +632,14 @@ public function testUpdateWithSoftDelete(): void
public function testDelete(): void
{
- $database = m::mock(Database::class);
- $collection = m::mock(Collection::class);
- $database->shouldReceive('selectCollection')
+ $database = $this->createMock(Database::class);
+ $collection = $this->createMock(Collection::class);
+ $database->expects($this->once())
+ ->method('selectCollection')
->with('collection_indexable')
- ->andReturn($collection);
- $collection->shouldReceive('deleteMany')
- ->once()
+ ->willReturn($collection);
+ $collection->expects($this->once())
+ ->method('deleteMany')
->with(['_id' => ['$in' => ['key_1', 'key_2']]]);
$engine = new ScoutEngine($database, softDelete: false);
@@ -646,13 +657,14 @@ public function testDeleteWithRemoveableScoutCollection(): void
$job = unserialize(serialize($job));
- $database = m::mock(Database::class);
- $collection = m::mock(Collection::class);
- $database->shouldReceive('selectCollection')
+ $database = $this->createMock(Database::class);
+ $collection = $this->createMock(Collection::class);
+ $database->expects($this->once())
+ ->method('selectCollection')
->with('collection_indexable')
- ->andReturn($collection);
- $collection->shouldReceive('deleteMany')
- ->once()
+ ->willReturn($collection);
+ $collection->expects($this->once())
+ ->method('deleteMany')
->with(['_id' => ['$in' => ['key_5']]]);
$engine = new ScoutEngine($database, softDelete: false);
From 583200745cd698ad03ae0025aa928f84c64fc6e8 Mon Sep 17 00:00:00 2001
From: Ivan Todorovic
Date: Tue, 1 Apr 2025 13:36:48 +0200
Subject: [PATCH 9/9] Remove manual dirty _id check when updating a model
(#3329)
---
src/Query/Builder.php | 7 -------
tests/Ticket/GH3326Test.php | 42 +++++++++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 7 deletions(-)
create mode 100644 tests/Ticket/GH3326Test.php
diff --git a/src/Query/Builder.php b/src/Query/Builder.php
index f613b6467..5c873380b 100644
--- a/src/Query/Builder.php
+++ b/src/Query/Builder.php
@@ -783,13 +783,6 @@ public function update(array $values, array $options = [])
unset($values[$key]);
}
- // Since "id" is an alias for "_id", we prevent updating it
- foreach ($values as $fields) {
- if (array_key_exists('id', $fields)) {
- throw new InvalidArgumentException('Cannot update "id" field.');
- }
- }
-
return $this->performUpdate($values, $options);
}
diff --git a/tests/Ticket/GH3326Test.php b/tests/Ticket/GH3326Test.php
new file mode 100644
index 000000000..d3f339acc
--- /dev/null
+++ b/tests/Ticket/GH3326Test.php
@@ -0,0 +1,42 @@
+foo = 'bar';
+ $model->save();
+
+ $fresh = $model->fresh();
+
+ $this->assertEquals('bar', $fresh->foo);
+ $this->assertEquals('written-in-created', $fresh->extra);
+ }
+}
+
+class GH3326Model extends Model
+{
+ protected $connection = 'mongodb';
+ protected $collection = 'test_gh3326';
+ protected $guarded = [];
+
+ protected static function booted(): void
+ {
+ static::created(function ($model) {
+ $model->extra = 'written-in-created';
+ $model->saveQuietly();
+ });
+ }
+}