@@ -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
9595operator 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+
97110Examples
98111--------
99112
@@ -256,3 +269,70 @@ 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`
338+
0 commit comments