Skip to content

Commit 970a913

Browse files
authored
DOCS-14267 Ambiguous Operator - Backport v4.0 (#500)
1 parent 7160ca5 commit 970a913

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

source/reference/operator/update/positional.txt

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,19 @@ However, if the negated portion of the query is inside of an
9494
:query:`$elemMatch` expression, then you *can* use the positional
9595
operator to update this field.
9696

97+
Multiple Array Matches
98+
~~~~~~~~~~~~~~~~~~~~~~~
99+
100+
The positional :update:`$` update operator behaves ambiguously when filtering
101+
on multiple array fields.
102+
103+
When the server executes an update method, it first runs a query to determine
104+
which documents you want to update. If the update filters documents on multiple
105+
array fields, the subsequent call to the positional :update:`$` update operator
106+
doesn't always update the required position in the array.
107+
108+
For more information, see the :ref:`example <multiple-array-match>`.
109+
97110
Examples
98111
--------
99112

@@ -256,3 +269,69 @@ criteria, namely the second embedded document in the array:
256269

257270
.. seealso:: :method:`db.collection.update()`,
258271
:method:`db.collection.findAndModify()`, :query:`$elemMatch()`
272+
273+
.. _multiple-array-match:
274+
275+
Update with Multiple Array Matches
276+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
277+
278+
The positional :update:`$` update operator behaves ambiguously when the
279+
query has multiple array fields to filter documents in the collection.
280+
281+
Consider a document in the ``students_deans_list`` collection, which holds
282+
arrays of student information:
283+
284+
.. code-block:: javascript
285+
286+
db.students_deans_list.insertMany( [
287+
{
288+
_id: 8,
289+
activity_ids: [ 1, 2 ],
290+
grades: [ 90, 95 ],
291+
deans_list: [ 2021, 2020 ]
292+
}
293+
] )
294+
295+
In the following example, the user attempts to modify the ``deans_list`` field,
296+
filtering documents using the ``activity_ids``, ``deans_list``, and ``grades``
297+
fields, and updating the 2021 value in the ``deans_list`` field to 2022:
298+
299+
.. code-block:: javascript
300+
301+
db.students_deans_list.updateOne(
302+
{ activity_ids: 1, grades: 95, deans_list: 2021 },
303+
{ $set: { "deans_list.$": 2022 } }
304+
)
305+
306+
When the server executes the ``updateOne`` method above, it filters
307+
the available documents using values in the supplied array fields.
308+
Although the ``deans_list`` field is used in the filter, it is not the field
309+
used by the positional :update:`$` update operator to determine which position
310+
in the array to update:
311+
312+
.. code-block:: javascript
313+
314+
db.students_deans_list.find( { _id: 8 } )
315+
316+
Example output:
317+
318+
.. code-block:: javascript
319+
320+
{
321+
_id: 8,
322+
activity_ids: [ 1, 2 ],
323+
grades: [ 90, 95 ],
324+
deans_list: [ 2021, 2022 ]
325+
}
326+
327+
The ``updateOne`` method matched the ``deans_list`` field on 2021, but the
328+
positional :update:`$` update operator instead changed the 2020 value to 2022.
329+
330+
To avoid unexpected results when matching on multiple arrays, instead
331+
use the filtered positional operator :update:`$[<identifier>]`.
332+
333+
.. seealso::
334+
335+
- :method:`db.collection.updateMany()`
336+
- :method:`db.collection.findAndModify()`
337+
- :query:`$elemMatch`

0 commit comments

Comments
 (0)