Skip to content

Commit cbc3aa8

Browse files
committed
DOCSP-15179-DOCS-9187 upsert with unique index refactor
1 parent 0531236 commit cbc3aa8

File tree

6 files changed

+209
-136
lines changed

6 files changed

+209
-136
lines changed

source/includes/extracts-parameter-upsert.yaml

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,34 @@ content: |
88
99
- Updates a single document that matches the ``{{queryOrFilter}}``.
1010
11-
To avoid multiple upserts, ensure that the ``{{queryOrFilter}}`` fields
12-
are :ref:`uniquely indexed <index-type-unique>`.
11+
{{usageWithMulti}}
12+
13+
To avoid multiple :term:`upserts <upsert>`, ensure that the
14+
``{{queryOrFilter}}`` field(s) are :ref:`uniquely indexed
15+
<index-type-unique>`. {{uniqueIndexExample}}
16+
17+
Defaults to ``false``, which does *not* insert a new document when no
18+
match is found.
1319
14-
Defaults to ``false``.
1520
replacement:
1621
conjunction: ''
1722
returnNewDocument: ''
23+
usageWithMulti: ''
24+
uniqueIndexExample: ''
25+
---
26+
ref: findAndModify-behavior-command
27+
source:
28+
file: extracts-parameter-upsert.yaml
29+
ref: _update-single-upsert-behavior
30+
replacement:
31+
upsertMethod: ":dbcommand:`findAndModify`"
32+
queryOrFilter: query
33+
uniqueIndexExample: "See :ref:`upsert-and-unique-index-dbcommand` for
34+
an example."
35+
conjunction: "Used in conjunction with the ``update`` field.
36+
37+
38+
"
1839
---
1940
ref: findAndModify-behavior-method
2041
source:
@@ -23,11 +44,39 @@ source:
2344
replacement:
2445
upsertMethod: ":method:`~db.collection.findAndModify()`"
2546
queryOrFilter: query
47+
uniqueIndexExample: "See :ref:`upsert-and-unique-index` for an
48+
example."
2649
conjunction: "Used in conjunction with the ``update`` field.
2750
2851
2952
"
3053
---
54+
ref: update-upsert-behavior-command
55+
source:
56+
file: extracts-parameter-upsert.yaml
57+
ref: _update-single-upsert-behavior
58+
replacement:
59+
upsertMethod: ":dbcommand:`update`"
60+
queryOrFilter: query
61+
usageWithMulti: "If both ``upsert`` and ``multi`` are true and no
62+
documents match the query, the update operation inserts only a
63+
single document."
64+
uniqueIndexExample: "See :ref:`update-command-behaviors-unique-index`
65+
for an example."
66+
---
67+
ref: update-upsert-behavior-method
68+
source:
69+
file: extracts-parameter-upsert.yaml
70+
ref: _update-single-upsert-behavior
71+
replacement:
72+
upsertMethod: ":method:`~db.collection.update()`"
73+
queryOrFilter: query
74+
usageWithMulti: "If both ``upsert`` and ``multi`` are true and no
75+
documents match the query, the update operation inserts only a
76+
single document."
77+
uniqueIndexExample: "See :ref:`update-with-unique-indexes` for an
78+
example."
79+
---
3180
ref: findOneAndUpdate-behavior-method
3281
source:
3382
file: extracts-parameter-upsert.yaml
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
ref: _upsert-unique-index-base
2+
content: |
3+
4+
When using the {{upsert}} option with the {{command}}
5+
{{commandOrMethod}}, **and not** using a :ref:`unique index
6+
<index-type-unique>` on the query field(s), multiple
7+
instances of {{aOrAn}} {{command}} operation with similar query
8+
field(s) could result in duplicate documents being inserted in
9+
certain circumstances.
10+
11+
Consider an example where no document with the name ``Andy`` exists
12+
and multiple clients issue the following command at roughly the same
13+
time:
14+
15+
{{codeExample}}
16+
17+
If all {{command}} operations finish the query phase
18+
before any client successfully inserts data, **and** there is no
19+
:ref:`unique index <index-type-unique>` on the ``name`` field, each
20+
{{command}} operation may result in an insert, creating multiple
21+
documents with ``name: Andy``.
22+
23+
To ensure that only one such document is created, and the other
24+
{{command}} operations update this new document instead, create a
25+
:ref:`unique index <index-type-unique>` on the ``name`` field. This
26+
guarantees that only one document with ``name: Andy`` is permitted
27+
in the collection.
28+
29+
With this unique index in place, the multiple {{command}} operations
30+
now exhibit the following behavior:
31+
32+
- Exactly one {{command}} operation will successfully insert a new
33+
document.
34+
35+
- All other {{command}} operations will update the newly-inserted
36+
document, incrementing the ``score`` value.
37+
38+
---
39+
ref: upsert-unique-index-findAndModify-command
40+
source:
41+
file: extracts-upsert-unique-index.yaml
42+
ref: _upsert-unique-index-base
43+
replacement:
44+
command: ":dbcommand:`findAndModify`"
45+
commandOrMethod: "command"
46+
aOrAn: "a"
47+
upsert: "``upsert: true``"
48+
codeExample: |
49+
50+
.. code-block:: javascript
51+
52+
db.runCommand(
53+
{
54+
findAndModify: "people",
55+
query: { name: "Andy" },
56+
update: { $inc: { score: 1 } },
57+
upsert: true
58+
}
59+
)
60+
61+
---
62+
ref: upsert-unique-index-findAndModify-method
63+
source:
64+
file: extracts-upsert-unique-index.yaml
65+
ref: _upsert-unique-index-base
66+
replacement:
67+
command: ":method:`~db.collection.findOneAndUpdate()`"
68+
commandOrMethod: "method"
69+
aOrAn: "a"
70+
upsert: "``upsert: true``"
71+
codeExample: |
72+
73+
.. code-block:: javascript
74+
75+
db.people.findAndModify(
76+
{
77+
query: { name: "Andy" },
78+
update: { $inc: { score: 1 } },
79+
upsert: true
80+
}
81+
)
82+
83+
---
84+
ref: upsert-unique-index-update-command
85+
source:
86+
file: extracts-upsert-unique-index.yaml
87+
ref: _upsert-unique-index-base
88+
replacement:
89+
command: ":dbcommand:`update`"
90+
commandOrMethod: "command"
91+
aOrAn: "an"
92+
upsert: ":ref:`upsert: true <update-command-upsert>`"
93+
codeExample: |
94+
95+
.. code-block:: javascript
96+
97+
db.runCommand(
98+
{
99+
update: "people",
100+
updates: [
101+
{ q: { name: "Andy" }, u: { $inc: { score: 1 } }, multi: true, upsert: true }
102+
]
103+
}
104+
)
105+
106+
---
107+
ref: upsert-unique-index-update-method
108+
source:
109+
file: extracts-upsert-unique-index.yaml
110+
ref: _upsert-unique-index-base
111+
replacement:
112+
command: ":method:`~db.collection.update()`"
113+
commandOrMethod: "method"
114+
aOrAn: "a"
115+
upsert: ":ref:`upsert: true <update-upsert>`"
116+
codeExample: |
117+
118+
.. code-block:: javascript
119+
120+
db.people.update(
121+
{ name: "Andy" },
122+
{ $inc: { score: 1 } },
123+
{
124+
upsert: true,
125+
multi: true
126+
}
127+
)
128+
129+
...

source/reference/command/findAndModify.txt

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ Definition
157157

158158
- boolean
159159

160-
- .. include:: /includes/extracts/findAndModify-behavior-method.rst
160+
- .. include:: /includes/extracts/findAndModify-behavior-command.rst
161161

162162

163163

@@ -357,49 +357,12 @@ following:
357357
Behavior
358358
--------
359359

360-
Upsert and Unique Index
361-
~~~~~~~~~~~~~~~~~~~~~~~
360+
.. _upsert-and-unique-index-dbcommand:
362361

363-
When the :dbcommand:`findAndModify` command includes the ``upsert:
364-
true`` option **and** the query field(s) is not uniquely indexed, the
365-
command could insert a document multiple times in certain circumstances.
362+
Upsert with Unique Index
363+
~~~~~~~~~~~~~~~~~~~~~~~~
366364

367-
Consider an example where no document with the name ``Andy`` exists and
368-
multiple clients issue the following command:
369-
370-
.. code-block:: javascript
371-
372-
db.runCommand(
373-
{
374-
findAndModify: "people",
375-
query: { name: "Andy" },
376-
sort: { rating: 1 },
377-
update: { $inc: { score: 1 } },
378-
upsert: true
379-
}
380-
)
381-
382-
If all the commands finish the ``query`` phase before any command
383-
starts the ``modify`` phase, **and** there is no unique index on the
384-
``name`` field, the commands may each perform an upsert, creating
385-
multiple duplicate documents.
386-
387-
To prevent the creation of multiple duplicate documents,
388-
create a :ref:`unique index <index-type-unique>` on
389-
the ``name`` field. With the unique index in place, then the multiple
390-
:dbcommand:`findAndModify` commands will exhibit one of the
391-
following behaviors:
392-
393-
- Exactly one :dbcommand:`findAndModify` successfully inserts a
394-
new document.
395-
396-
- Zero or more :dbcommand:`findAndModify` commands update the
397-
newly inserted document.
398-
399-
- Zero or more :dbcommand:`findAndModify` commands fail when
400-
they attempt to insert a duplicate. If the command fails due to
401-
a unique index constraint violation, you can retry the command.
402-
Absent a delete of the document, the retry should not fail.
365+
.. include:: /includes/extracts/upsert-unique-index-findAndModify-command.rst
403366

404367
.. _cmd-findAndModify-sharded-collection:
405368

source/reference/command/update.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,7 @@ Each document contains the following fields:
193193

194194
- .. _update-command-upsert:
195195

196-
Optional. If ``true``, perform an insert if no documents match the query. If
197-
both ``upsert`` and ``multi`` are true and no documents match the
198-
query, the update operation inserts only a single document.
196+
.. include:: /includes/extracts/update-upsert-behavior-command.rst
199197

200198
* - ``multi``
201199

@@ -386,6 +384,13 @@ For example:
386384

387385
For examples, see :ref:`update-command-example-agg`.
388386

387+
.. _update-command-behaviors-unique-index:
388+
389+
Upsert with Unique Index
390+
~~~~~~~~~~~~~~~~~~~~~~~~
391+
392+
.. include:: /includes/extracts/upsert-unique-index-update-command.rst
393+
389394
Limits
390395
~~~~~~
391396

source/reference/method/db.collection.findAndModify.txt

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -288,47 +288,10 @@ For more information on projection, see also:
288288

289289
.. _upsert-and-unique-index:
290290

291-
Upsert and Unique Index
292-
~~~~~~~~~~~~~~~~~~~~~~~
291+
Upsert with Unique Index
292+
~~~~~~~~~~~~~~~~~~~~~~~~
293293

294-
When :method:`~db.collection.findAndModify()` includes the ``upsert:
295-
true`` option **and** the query field(s) is not uniquely indexed, the
296-
method could insert a document multiple times in certain circumstances.
297-
298-
In the following example, no document with the name ``Andy`` exists,
299-
and multiple clients issue the following command:
300-
301-
.. code-block:: javascript
302-
303-
db.people.findAndModify({
304-
query: { name: "Andy" },
305-
sort: { rating: 1 },
306-
update: { $inc: { score: 1 } },
307-
upsert: true
308-
})
309-
310-
Then, if these clients' :method:`~db.collection.findAndModify()`
311-
methods finish the ``query`` phase before any command starts the
312-
``modify`` phase, **and** there is no unique index on the ``name``
313-
field, the commands may all perform an upsert, creating
314-
multiple duplicate documents.
315-
316-
To prevent the creation of multiple duplicate documents with the same
317-
name, create a :ref:`unique index <index-type-unique>` on the ``name``
318-
field. With this unique index in place, the multiple methods will
319-
exhibit one of the following behaviors:
320-
321-
- Exactly one :method:`~db.collection.findAndModify()`
322-
successfully inserts a new document.
323-
324-
- Zero or more :method:`~db.collection.findAndModify()` methods
325-
update the newly inserted document.
326-
327-
- Zero or more :method:`~db.collection.findAndModify()` methods fail
328-
when they attempt to insert documents with the same name. If the
329-
method fails due to the unique index constraint violation on the
330-
``name`` field, you can retry the method. Absent a delete of the
331-
document, the retry should not fail.
294+
.. include:: /includes/extracts/upsert-unique-index-findAndModify-method.rst
332295

333296
.. _method-findAndModify-sharded-collection:
334297

0 commit comments

Comments
 (0)