diff --git a/docs/fundamentals/write-operations.txt b/docs/fundamentals/write-operations.txt index 2e87677d1..1afad76dc 100644 --- a/docs/fundamentals/write-operations.txt +++ b/docs/fundamentals/write-operations.txt @@ -9,7 +9,7 @@ Write Operations :values: tutorial .. meta:: - :keywords: insert, insert one, update, update one, upsert, code example, mass assignment, eloquent model + :keywords: insert, insert one, update, update one, upsert, code example, mass assignment, push, pull, eloquent model .. contents:: On this page :local: @@ -167,6 +167,7 @@ This section provides examples of the following update operations: - :ref:`Update a document ` - :ref:`Update multiple documents ` - :ref:`Update or insert in a single operation ` +- :ref:`Update arrays in a document ` .. _laravel-modify-documents-update-one: @@ -292,7 +293,6 @@ matching documents exist: .. input:: /includes/fundamentals/write-operations/WriteOperationsTest.php :language: php :dedent: - :emphasize-lines: 4 :start-after: begin model upsert :end-before: end model upsert @@ -311,3 +311,172 @@ matching documents exist: "ticketsSold": 4000, "updated_at": ... } + +.. _laravel-modify-documents-arrays: + +Update Arrays in a Document +--------------------------- + +In this section, you can see examples of the following operations that +update array values in a MongoDB document: + +- :ref:`Add values to an array ` +- :ref:`Remove values from an array ` +- :ref:`Update the value of an array element ` + +These examples modify the sample document created by the following insert +operation: + +.. literalinclude:: /includes/fundamentals/write-operations/WriteOperationsTest.php + :language: php + :dedent: + :start-after: begin array example document + :end-before: end array example document + +.. _laravel-modify-documents-add-array-values: + +Add Values to an Array Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section shows how to use the ``push()`` method to add values to an array +in a MongoDB document. You can pass one or more values to add and set the +optional parameter ``unique`` to ``true`` to skip adding any duplicate values +in the array. The following code example shows the structure of a ``push()`` +method call: + +.. code-block:: none + :copyable: false + + YourModel::where() + ->push( + , + [], // array or single value to add + unique: true); // whether to skip existing values + +The following example shows how to add the value ``"baroque"`` to +the ``genres`` array field of a matching document. Click the +:guilabel:`VIEW OUTPUT` button to see the updated document: + +.. io-code-block:: + + .. input:: /includes/fundamentals/write-operations/WriteOperationsTest.php + :language: php + :dedent: + :start-after: begin model array push + :end-before: end model array push + + .. output:: + :language: json + :visible: false + + { + "_id": "660eb...", + "performer": "Mitsuko Uchida", + "genres": [ + "classical", + "dance-pop", + + ], + "updated_at": ..., + "created_at": ... + } + + +.. _laravel-modify-documents-remove-array-values: + +Remove Values From an Array Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section shows how to use the ``pull()`` method to remove values from +an array in a MongoDB document. You can pass one or more values to remove +from the array. The following code example shows the structure of a +``pull()`` method call: + +.. code-block:: none + :copyable: false + + YourModel::where() + ->pull( + , + []); // array or single value to remove + +The following example shows how to remove array values ``"classical"`` and +``"dance-pop"`` from the ``genres`` array field. Click the +:guilabel:`VIEW OUTPUT` button to see the updated document: + +.. io-code-block:: + + .. input:: /includes/fundamentals/write-operations/WriteOperationsTest.php + :language: php + :dedent: + :start-after: begin model array pull + :end-before: end model array pull + + .. output:: + :language: json + :visible: false + + { + "_id": "660e...", + "performer": "Mitsuko Uchida", + "genres": [], + "updated_at": ..., + "created_at": ... + } + + +.. _laravel-modify-documents-update-array-values: + +Update the Value of an Array Element Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section shows how to use the ``$`` positional operator to update specific +array elements in a MongoDB document. The ``$`` operator represents the first +array element that matches the query. The following code example shows the +structure of a positional operator update call on a single matching document: + + +.. note:: + + Currently, {+odm-short+} offers this operation only on the ``DB`` facade + and not on the Eloquent ORM. + +.. code-block:: none + :copyable: false + + DB::connection('mongodb') + ->getCollection() + ->updateOne( + , + ['$set' => ['.$' => ]]); + + +The following example shows how to replace the array value ``"dance-pop"`` +with ``"contemporary"`` in the ``genres`` array field. Click the +:guilabel:`VIEW OUTPUT` button to see the updated document: + +.. io-code-block:: + + .. input:: /includes/fundamentals/write-operations/WriteOperationsTest.php + :language: php + :dedent: + :start-after: begin model array positional + :end-before: end model array positional + + .. output:: + :language: json + :visible: false + + { + "_id": "660e...", + "performer": "Mitsuko Uchida", + "genres": [ + "classical", + "contemporary" + ], + "updated_at": ..., + "created_at": ... + } + +To learn more about array update operators, see :manual:`Array Update Operators ` +in the {+server-docs-name+}. diff --git a/docs/includes/fundamentals/write-operations/WriteOperationsTest.php b/docs/includes/fundamentals/write-operations/WriteOperationsTest.php index 5f759ae6b..ef0e8d755 100644 --- a/docs/includes/fundamentals/write-operations/WriteOperationsTest.php +++ b/docs/includes/fundamentals/write-operations/WriteOperationsTest.php @@ -6,10 +6,12 @@ use App\Models\Concert; use Carbon\Carbon; +use Illuminate\Support\Facades\DB; use MongoDB\BSON\UTCDateTime; use MongoDB\Laravel\Tests\TestCase; use function count; +use function in_array; class WriteOperationsTest extends TestCase { @@ -238,4 +240,93 @@ public function testModelUpsert(): void $this->assertEquals('Jon Batiste', $result->performer); $this->assertEquals(4000, $result->ticketsSold); } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testModelPushArray(): void + { + require_once __DIR__ . '/Concert.php'; + Concert::truncate(); + + // begin array example document + Concert::create([ + 'performer' => 'Mitsuko Uchida', + 'genres' => ['classical', 'dance-pop'], + ]); + // end array example document + + // begin model array push + Concert::where('performer', 'Mitsuko Uchida') + ->push( + 'genres', + ['baroque'], + ); + // end model array push + + $result = Concert::first(); + + $this->assertInstanceOf(Concert::class, $result); + $this->assertContains('baroque', $result->genres); + } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testModelPullArray(): void + { + require_once __DIR__ . '/Concert.php'; + Concert::truncate(); + + Concert::create([ + 'performer' => 'Mitsuko Uchida', + 'genres' => [ 'classical', 'dance-pop' ], + ]); + + // begin model array pull + Concert::where('performer', 'Mitsuko Uchida') + ->pull( + 'genres', + ['dance-pop', 'classical'], + ); + // end model array pull + + $result = Concert::first(); + + $this->assertInstanceOf(Concert::class, $result); + $this->assertEmpty($result->genres); + } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testModelPositional(): void + { + require_once __DIR__ . '/Concert.php'; + Concert::truncate(); + + Concert::create([ + 'performer' => 'Mitsuko Uchida', + 'genres' => [ 'classical', 'dance-pop' ], + ]); + + // begin model array positional + $match = ['performer' => 'Mitsuko Uchida', 'genres' => 'dance-pop']; + $update = ['$set' => ['genres.$' => 'contemporary']]; + + DB::connection('mongodb') + ->getCollection('concerts') + ->updateOne($match, $update); + // end model array positional + + $result = Concert::first(); + + $this->assertInstanceOf(Concert::class, $result); + $this->assertContains('classical', $result->genres); + $this->assertContains('contemporary', $result->genres); + $this->assertFalse(in_array('dance-pop', $result->genres)); + } }