@@ -94,6 +94,19 @@ However, if the negated portion of the query is inside of an
94
94
:query:`$elemMatch` expression, then you *can* use the positional
95
95
operator to update this field.
96
96
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
+
97
110
Examples
98
111
--------
99
112
@@ -256,3 +269,69 @@ criteria, namely the second embedded document in the array:
256
269
257
270
.. seealso:: :method:`db.collection.update()`,
258
271
: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