diff --git a/source/reference/command/findAndModify.txt b/source/reference/command/findAndModify.txt index daf70ba12cc..68e59fca6f6 100644 --- a/source/reference/command/findAndModify.txt +++ b/source/reference/command/findAndModify.txt @@ -20,10 +20,10 @@ Definition The command has the following syntax: - .. code-block:: javascript + .. code-block:: none { - findAndModify: , + findAndModify: , query: , sort: , remove: , @@ -92,13 +92,12 @@ The return document contains the following fields: Behavior -------- +Upsert and Unique Index +~~~~~~~~~~~~~~~~~~~~~~~ + When the :dbcommand:`findAndModify` command includes the ``upsert: true`` option **and** the query field(s) is not uniquely indexed, the command could insert a document multiple times in certain circumstances. -For instance, if multiple clients issue the :dbcommand:`findAndModify` -command and these commands complete the ``find`` phase before any one -starts the ``modify`` phase, these commands could insert the same -document. Consider an example where no document with the name ``Andy`` exists and multiple clients issue the following command: @@ -117,19 +116,22 @@ multiple clients issue the following command: If all the commands finish the ``query`` phase before any command starts the ``modify`` phase, **and** there is no unique index on the -``name`` field, the commands may all result in an insert. To prevent +``name`` field, the commands may all perform an upsert, creating +multiple duplicate documents. + +To prevent this condition, create a :ref:`unique index ` on the ``name`` field. With the unique index in place, then the multiple -:dbcommand:`findAndModify` commands would observe one of the +:dbcommand:`findAndModify` commands will exhibit one of the following behaviors: -- Exactly one :dbcommand:`findAndModify` would successfully insert a +- Exactly one :dbcommand:`findAndModify` successfully inserts a new document. -- Zero or more :dbcommand:`findAndModify` commands would update the +- Zero or more :dbcommand:`findAndModify` commands update the newly inserted document. -- Zero or more :dbcommand:`findAndModify` commands would fail when +- Zero or more :dbcommand:`findAndModify` commands fail when they attempted to insert a duplicate. If the command fails due to a unique index constraint violation, you can retry the command. Absent a delete of the document, the retry should not fail. diff --git a/source/reference/method/db.collection.findAndModify-param.yaml b/source/reference/method/db.collection.findAndModify-param.yaml index 7fae10ccc4b..5ac2958b3c7 100644 --- a/source/reference/method/db.collection.findAndModify-param.yaml +++ b/source/reference/method/db.collection.findAndModify-param.yaml @@ -12,7 +12,7 @@ description: | employs the same :ref:`query selectors ` as used in the :method:`db.collection.find()` method. Although the query may match multiple documents, |operation| - will select only one document to modify. + **will only select one document to modify**. --- object: name: db.collection.findAndModify() @@ -100,7 +100,8 @@ description: | When ``true``, |operation| creates a new document if no document matches the ``query``, or if documents match the ``query``, |operation| performs an - update. + update. To avoid multiple upserts, ensure the ``query`` fields + are :ref:`uniquely indexed `. The default is ``false``. ... diff --git a/source/reference/method/db.collection.findAndModify.txt b/source/reference/method/db.collection.findAndModify.txt index f0a930d2fdd..595e5318e7d 100644 --- a/source/reference/method/db.collection.findAndModify.txt +++ b/source/reference/method/db.collection.findAndModify.txt @@ -65,8 +65,8 @@ modified document. creates a new document. If ``new`` is ``false``, **and** a ``sort`` option, the method returns an empty document ``{}``. -Behaviors ---------- +Behavior +-------- .. _upsert-and-unique-index: @@ -76,10 +76,6 @@ Upsert and Unique Index When :method:`~db.collection.findAndModify()` includes the ``upsert: true`` option **and** the query field(s) is not uniquely indexed, the method could insert a document multiple times in certain circumstances. -For instance, if multiple clients each invoke the method with the same -``query`` condition and these methods complete the ``find`` phase -before any of methods perform the ``modify`` phase, these methods could -result in the insertion of the same document. In the following example, no document with the name ``Andy`` exists, and multiple clients issue the following command: @@ -96,19 +92,22 @@ and multiple clients issue the following command: Then, if these clients' :method:`~db.collection.findAndModify()` methods finish the ``query`` phase before any command starts the ``modify`` phase, **and** there is no unique index on the ``name`` -field, the commands may all perform an upsert. To prevent this +field, the commands may all perform an upsert, creating +multiple duplicate documents. + +To prevent this condition, create a :ref:`unique index ` on the ``name`` field. With the unique index in place, the multiple methods -would observe one of the following behaviors: +will exhibit one of the following behaviors: -- Exactly one :method:`~db.collection.findAndModify()` would - successfully insert a new document. +- Exactly one :method:`~db.collection.findAndModify()` + successfully inserts a new document. - Zero or more :method:`~db.collection.findAndModify()` methods - would update the newly inserted document. + update the newly inserted document. - Zero or more :method:`~db.collection.findAndModify()` methods - would fail when they attempted to insert a duplicate. If the + fail when they attempted to insert a duplicate. If the method fails due to a unique index constraint violation, you can retry the method. Absent a delete of the document, the retry should not fail.