Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 4.8 into 5.0 #3098

Merged
merged 4 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/feature-compatibility.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ The following Eloquent methods are not supported in {+odm-short+}:
- *Unsupported as MongoDB uses ObjectIDs*

* - Upserts
- *Unsupported*
- ✓ See :ref:`laravel-mongodb-query-builder-upsert`.

* - Update Statements
- ✓
Expand Down Expand Up @@ -216,7 +216,7 @@ Eloquent Features
- ✓

* - Upserts
- *Unsupported, but you can use the createOneOrFirst() method*
- ✓ See :ref:`laravel-modify-documents-upsert`.

* - Deleting Models
- ✓
Expand Down
90 changes: 86 additions & 4 deletions docs/fundamentals/write-operations.txt
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,88 @@ An **upsert** operation lets you perform an update or insert in a single
operation. This operation streamlines the task of updating a document or
inserting one if it does not exist.

Starting in v4.7, you can perform an upsert operation by using either of
the following methods:

- ``upsert()``: When you use this method, you can perform a **batch
upsert** to change or insert multiple documents in one operation.

- ``update()``: When you use this method, you must specify the
``upsert`` option to update all documents that match the query filter
or insert one document if no documents are matched. Only this upsert method
is supported in versions v4.6 and earlier.

Upsert Method
~~~~~~~~~~~~~

The ``upsert(array $values, array|string $uniqueBy, array|null
$update)`` method accepts the following parameters:

- ``$values``: Array of fields and values that specify documents to update or insert.
- ``$uniqueBy``: List of fields that uniquely identify documents in your
first array parameter.
- ``$update``: Optional list of fields to update if a matching document
exists. If you omit this parameter, {+odm-short+} updates all fields.

To specify an upsert in the ``upsert()`` method, set parameters
as shown in the following code example:

.. code-block:: php
:copyable: false

YourModel::upsert(
[/* documents to update or insert */],
'/* unique field */',
[/* fields to update */],
);

Example
^^^^^^^

This example shows how to use the ``upsert()``
method to perform an update or insert in a single operation. Click the
:guilabel:`{+code-output-label+}` button to see the resulting data changes when
there is a document in which the value of ``performer`` is ``'Angel
Olsen'`` in the collection already:

.. io-code-block::

.. input:: /includes/fundamentals/write-operations/WriteOperationsTest.php
:language: php
:dedent:
:start-after: begin model upsert
:end-before: end model upsert

.. output::
:language: json
:visible: false

{
"_id": "...",
"performer": "Angel Olsen",
"venue": "State Theatre",
"genres": [
"indie",
"rock"
],
"ticketsSold": 275,
"updated_at": ...
},
{
"_id": "...",
"performer": "Darondo",
"venue": "Cafe du Nord",
"ticketsSold": 300,
"updated_at": ...
}

In the document in which the value of ``performer`` is ``'Angel
Olsen'``, the ``venue`` field value is not updated, as the upsert
specifies that the update applies only to the ``ticketsSold`` field.

Update Method
~~~~~~~~~~~~~

To specify an upsert in an ``update()`` method, set the ``upsert`` option to
``true`` as shown in the following code example:

Expand All @@ -278,8 +360,8 @@ following actions:
- If the query matches zero documents, the ``update()`` method inserts a
document that contains the update data and the equality match criteria data.

Upsert Example
~~~~~~~~~~~~~~
Example
^^^^^^^

This example shows how to pass the ``upsert`` option to the ``update()``
method to perform an update or insert in a single operation. Click the
Expand All @@ -291,8 +373,8 @@ matching documents exist:
.. input:: /includes/fundamentals/write-operations/WriteOperationsTest.php
:language: php
:dedent:
:start-after: begin model upsert
:end-before: end model upsert
:start-after: begin model update upsert
:end-before: end model update upsert

.. output::
:language: json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,22 +217,55 @@ public function testModelUpdateMultiple(): void
}
}

/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testModelUpsert(): void
{
require_once __DIR__ . '/Concert.php';
Concert::truncate();

// Pre-existing sample document
Concert::create([
'performer' => 'Angel Olsen',
'venue' => 'State Theatre',
'genres' => [ 'indie', 'rock' ],
'ticketsSold' => 150,
]);

// begin model upsert
Concert::upsert([
['performer' => 'Angel Olsen', 'venue' => 'Academy of Music', 'ticketsSold' => 275],
['performer' => 'Darondo', 'venue' => 'Cafe du Nord', 'ticketsSold' => 300],
], 'performer', ['ticketsSold']);
// end model upsert

$this->assertSame(2, Concert::count());

$this->assertSame(275, Concert::where('performer', 'Angel Olsen')->first()->ticketsSold);
$this->assertSame('State Theatre', Concert::where('performer', 'Angel Olsen')->first()->venue);

$this->assertSame(300, Concert::where('performer', 'Darondo')->first()->ticketsSold);
$this->assertSame('Cafe du Nord', Concert::where('performer', 'Darondo')->first()->venue);
}

/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testModelUpsert(): void
public function testModelUpdateUpsert(): void
{
require_once __DIR__ . '/Concert.php';
Concert::truncate();

// begin model upsert
// begin model update upsert
Concert::where(['performer' => 'Jon Batiste', 'venue' => 'Radio City Music Hall'])
->update(
['genres' => ['R&B', 'soul'], 'ticketsSold' => 4000],
['upsert' => true],
);
// end model upsert
// end model update upsert

$result = Concert::first();

Expand Down
25 changes: 24 additions & 1 deletion docs/includes/query-builder/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,29 @@ function (Collection $collection) {
public function testUpsert(): void
{
// begin upsert
$result = DB::table('movies')
->upsert(
[
['title' => 'Inspector Maigret', 'recommended' => false, 'runtime' => 128],
['title' => 'Petit Maman', 'recommended' => true, 'runtime' => 72],
],
'title',
'recommended',
);
// end upsert

$this->assertSame(2, $result);

$this->assertSame(119, DB::table('movies')->where('title', 'Inspector Maigret')->first()['runtime']);
$this->assertSame(false, DB::table('movies')->where('title', 'Inspector Maigret')->first()['recommended']);

$this->assertSame(true, DB::table('movies')->where('title', 'Petit Maman')->first()['recommended']);
$this->assertSame(72, DB::table('movies')->where('title', 'Petit Maman')->first()['runtime']);
}

public function testUpdateUpsert(): void
{
// begin update upsert
$result = DB::table('movies')
->where('title', 'Will Hunting')
->update(
Expand All @@ -516,7 +539,7 @@ public function testUpsert(): void
],
['upsert' => true],
);
// end upsert
// end update upsert

$this->assertIsInt($result);
}
Expand Down
Loading
Loading