diff --git a/source/reference/command/findAndModify.txt b/source/reference/command/findAndModify.txt index fd8ec16bb89..8e8ebdcabd8 100644 --- a/source/reference/command/findAndModify.txt +++ b/source/reference/command/findAndModify.txt @@ -4,6 +4,10 @@ findAndModify .. default-domain:: mongodb +.. EDITS to findAndModify.txt must be carried over (possibly w + modifications) to the method db.collection.findAndModify.txt and + vice versa + .. dbcommand:: findAndModify The :dbcommand:`findAndModify` command atomically modifies and @@ -14,12 +18,25 @@ findAndModify The command has the following syntax: - .. code-block:: javascript + .. code-block:: none + + { + findAndModify: , + query: , + sort: , + remove: , + update: , + new: , + fields: , + upsert: + } - { findAndModify: , } + The :dbcommand:`findAndModify` command takes the following + fields: - The :dbcommand:`findAndModify` command takes the following are - sub-document ``options``: + :field string findAndModify: + + Required. The collection against which to run the command. :field document query: @@ -30,12 +47,6 @@ findAndModify match multiple documents, :dbcommand:`findAndModify` will only select one document to modify. - The ``query`` field has the following syntax: - - .. code-block:: javascript - - query: { } - :field document sort: Optional. Determines which document the operation will @@ -43,23 +54,11 @@ findAndModify documents. :dbcommand:`findAndModify` will modify the first document in the sort order specified by this argument. - The ``sort`` field has the following syntax: - - .. code-block:: javascript - - sort: { field1: value1, field2: value2, ... } - :field boolean remove: Optional if ``update`` field exists. When ``true``, removes the selected document. The default is ``false``. - The ``remove`` field has the following syntax: - - .. code-block:: javascript - - remove: - :field document update: Optional if ``remove`` field exists. Performs an update of @@ -67,10 +66,6 @@ findAndModify :ref:`update operators ` or ``field: value`` specifications to modify the selected document. - .. code-block:: javascript - - update: { } - :field boolean new: Optional. When ``true``, returns the modified document rather @@ -78,79 +73,332 @@ findAndModify ignores the ``new`` option for ``remove`` operations. The default is ``false``. - .. code-block:: javascript - - new: - :field document fields: - Optional. A subset of fields to return. + Optional. A subset of fields to return. The ``fields`` + document specifies an inclusion of a field with ``1``, as in + the following: .. code-block:: javascript - fields: { field1: , field2: ... } + fields: { : 1, : 1, ... } + + See :ref:`projection `. :field boolean upsert: Optional. Used in conjunction with the ``update`` field. When ``true``, the :dbcommand:`findAndModify` command creates a new document if the ``query`` returns no documents. The - default is ``false``. + default is ``false``. - .. code-block:: javascript + The :dbcommand:`findAndModify` command returns a document, similar + to the following: - upsert: + .. code-block:: javascript - If you specify ``{ new: false }`` and the upsert operation - performs an insert operation, then the operation will return - a document that resembles the following: - - .. code-block:: javascript + { + lastErrorObject: { + updatedExisting: , + upserted: , + n: , + connectionId: , + err: , + ok: + } + value: , + ok: + } - { 'ok': 1.0, 'value': null } + The return document contains the following fields: - .. versionchanged:: 2.2 - Previously, ``upsert`` operations that performed inserts - returned an empty document (e.g. ``{ }``,) if ``new`` is - ``false``. See :ref:`the 2.2 release notes - <2.2-findandmodify-returns-null>` for more information. + - The ``lastErrorObject`` field that returns the details of the + command: - Consider the following example: + - The ``updatedExisting`` field **only** appears if the command is + either an ``update`` or an ``upsert``. - .. code-block:: javascript + - The ``upserted`` field **only** appears if the command is an + ``upsert``. - { findAndModify: "people", - query: { name: "Tom", state: "active", rating: { $gt: 10 } }, - sort: { rating: 1 }, - update: { $inc: { score: 1 } } - } + - The ``value`` field that returns either: + + - the original (i.e. pre-modification) document if ``new`` is + false, or - This command performs the following actions: + - the modified or inserted document if ``new: true``. - #. The ``query`` finds a document in the ``people`` collection where the - ``name`` field has the value ``Tom``, the ``state`` field has the - value ``active`` and the ``rating`` field has a value - :operator:`greater than <$gt>` 10. + - The ``ok`` field that returns the status of the command. + + .. note:: - #. The ``sort`` orders the results of the query in ascending order. + - If no document is found for the ``update`` or ``remove``, the + ``lastErrorObject`` does not appear in the return document and + the ``value`` is ``null``. - #. The update :operator:`increments <$inc>` the value of the - ``score`` field by 1. + .. code-block:: javascript - #. The command returns the original unmodified document - selected for this update. + { "value" : null, "ok" : 1 } + + - If no document is found for an ``upsert``, which means the + command performs an insert, and ``new`` is ``false``, **and** a + ``sort`` option is specified, all three fields + (``lastErrorObject``, ``value``, and ``ok``) appear but the + ``value`` is an empty document ``{}``. - The shell and many :term:`drivers ` provide a - :method:`findAndModify()` helper method. Using the shell helper, - this same operation can take the following form: + - If no document is found for an ``upsert``, which means the + command performs an insert, and ``new`` is ``false`` **and** a + ``sort`` option is **not** specified, all three fields + (``lastErrorObject``, ``value``, and ``ok``) appear but the + ``value`` is ``null``. + + .. versionchanged:: 2.2 + Previously, the command returned an empty document (e.g. + ``{}``) in the ``value`` field. See :ref:`the 2.2 release + notes <2.2-findandmodify-returns-null>` for more information. + + Consider the following examples: + + - The following command updates an existing document in the + ``people`` collection where the document matches the ``query`` + criteria: + + .. code-block:: javascript + + db.runCommand( + { + findAndModify: "people", + query: { name: "Tom", state: "active", rating: { $gt: 10 } }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } } + } + ) + + This command performs the following actions: + + #. The ``query`` finds a document in the ``people`` collection where the + ``name`` field has the value ``Tom``, the ``state`` field has + the value ``active`` and the ``rating`` field has a value + :operator:`greater than <$gt>` 10. + + #. The ``sort`` orders the results of the query in ascending order. + If multiple documents meet the ``query`` condition, the command + will select for modification the first document as ordered by + this ``sort``. + + #. The ``update`` :operator:`increments <$inc>` the value of the + ``score`` field by 1. + + #. The command returns a document with the following fields: + + - The ``lastErrorObject`` field that contains the details of + the command, including the field ``updatedExisting`` which is + ``true``, and + + - The ``value`` field that contains the original (i.e. + pre-modification) document selected for this update: + + .. code-block:: javascript + + { + "lastErrorObject" : { + "updatedExisting" : true, + "n" : 1, + "connectionId" : 1, + "err" : null, + "ok" : 1 + }, + "value" : { + "_id" : ObjectId("50f1d54e9beb36a0f45c6452"), + "name" : "Tom", + "state" : "active", + "rating" : 100, + "score" : 5 + }, + "ok" : 1 + } + + To return the modified document in the ``value`` field, add the + ``new:true`` option to the command. + + If no document match the ``query`` condition, the command + returns a document that contains ``null`` in the ``value`` + field: + + .. code-block:: javascript + + { "value" : null, "ok" : 1 } + + The :program:`mongo` shell and many :term:`drivers ` + provide a :method:`~db.collection.findAndModify()` helper method. + Using the shell helper, this previous operation can take the + following form: + + .. code-block:: javascript + + db.people.findAndModify( { + query: { name: "Tom", state: "active", rating: { $gt: 10 } }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } } + } ); + + However, the :method:`~db.collection.findAndModify()` shell helper + method returns just the unmodified document (or the modified + document if the ``new:true`` option had been set): + + .. code-block:: javascript + + { + "_id" : ObjectId("50f1d54e9beb36a0f45c6452"), + "name" : "Tom", + "state" : "active", + "rating" : 100, + "score" : 5 + } + + - The following :dbcommand:`findAndModify` command includes the + ``upsert: true`` option to insert a new document if no document + matches the ``query`` condition: + + .. code-block:: javascript + + db.runCommand( + { + findAndModify: "people", + query: { name: "Gus", state: "active", rating: 100 }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } }, + upsert: true + } + ) + + If the command does **not** find a matching document, the command + performs an upsert and returns a document with the following + fields: + + - The ``lastErrorObject`` field that contains the details of the + command, including the field ``upserted`` that contains the + ``ObjectId`` of the newly inserted document, and + + - The ``value`` field that contains an empty document ``{}`` as + the original document because the command included the ``sort`` + option: + + .. code-block:: sh + + { + "lastErrorObject" : { + "updatedExisting" : false, + "upserted" : ObjectId("50f2329d0092b46dae1dc98e"), + "n" : 1, + "connectionId" : 1, + "err" : null, + "ok" : 1 + }, + "value" : { + + }, + "ok" : 1 + } + + If the command did **not** include the ``sort`` option, the ``value`` field + would contain ``null``: + + .. code-block:: sh + + { + "value" : null, + "lastErrorObject" : { + "updatedExisting" : false, + "n" : 1, + "upserted" : ObjectId("5102f7540cb5c8be998c2e99") + }, + "ok" : 1 + } + + - The following :dbcommand:`findAndModify` command includes both + ``upsert: true`` option and the ``new:true`` option to return the + newly inserted document in the ``value`` field if a document + matching the ``query`` is not found: + + .. code-block:: javascript + + db.runCommand( + { + findAndModify: "people", + query: { name: "Pascal", state: "active", rating: 25 }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } }, + upsert: true, + new: true + } + ) + + The command returns the newly inserted document in the ``value`` + field: + + .. code-block:: sh + + { + "lastErrorObject" : { + "updatedExisting" : false, + "upserted" : ObjectId("50f47909444c11ac2448a5ce"), + "n" : 1, + "connectionId" : 1, + "err" : null, + "ok" : 1 + }, + "value" : { + "_id" : ObjectId("50f47909444c11ac2448a5ce"), + "name" : "Pascal", + "rating" : 25, + "score" : 1, + "state" : "active" + }, + "ok" : 1 + } + + When the :dbcommand:`findAndModify` command 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 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: .. code-block:: javascript - db.people.findAndModify( { - query: { name: "Tom", state: "active", rating: { $gt: 10 } }, - sort: { rating: 1 }, - update: { $inc: { score: 1 } } - } ); + db.runCommand( + { + findAndModify: "people", + query: { name: "Andy" }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } }, + upsert: true + } + ) + + 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 perform an upsert. 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 + following behaviors: + + - Exactly one :dbcommand:`findAndModify` would successfully insert a + new document. + + - Zero or more :dbcommand:`findAndModify` commands would update the + newly inserted document. + + - Zero or more :dbcommand:`findAndModify` commands would 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. .. warning:: diff --git a/source/reference/method/db.collection.findAndModify.txt b/source/reference/method/db.collection.findAndModify.txt index 15277a1a044..2de5632d6bd 100644 --- a/source/reference/method/db.collection.findAndModify.txt +++ b/source/reference/method/db.collection.findAndModify.txt @@ -4,13 +4,30 @@ db.collection.findAndModify() .. default-domain:: mongodb +.. EDITS to db.collection.findAndModify.txt must be carried over + (possibly w modifications) to the command findAndModify.txt and vice + versa + .. method:: db.collection.findAndModify The :method:`db.collection.findAndModify()` method atomically modifies and returns a single document. By default, the returned document does not include the modifications made on the update. To return the document with the modifications made on the update, use - the ``new`` option. + the ``new`` option. The :method:`~findAndModify()` method is a shell + helper around the :dbcommand:`findAndModify` command. + + .. code-block:: none + + db.collection.findAndModify( { + query: , + sort: , + remove: , + update: , + new: , + fields: , + upsert: + } ); The :method:`db.collection.findAndModify()` method takes a document parameter with the following subdocument fields: @@ -21,38 +38,21 @@ db.collection.findAndModify() modification. The ``query`` field employs the same :ref:`query selectors ` as used in the :method:`db.collection.find()` method. Although the query may - match multiple documents, :method:`findAndModify() ` will - only select one document to modify. - - The ``query`` field has the following syntax: - - .. code-block:: javascript - - query: { } - + match multiple documents, + :method:`~db.collection.findAndModify()` will only select one + document to modify. + :field document sort: - Optional. Determines which document the operation will - modify if the query selects multiple - documents. :dbcommand:`findAndModify() ` will modify the first - document in the sort order specified by this argument. - - The ``sort`` field has the following syntax: - - .. code-block:: javascript - - sort: { field1: value1, field2: value2, ... } + Optional. Determines which document the operation will modify + if the query selects multiple documents. + :method:`~db.collection.findAndModify()` will modify the + first document in the sort order specified by this argument. :field boolean remove: Optional if ``update`` field exists. When ``true``, removes the selected document. The default is ``false``. - - The ``remove`` field has the following syntax: - - .. code-block:: javascript - - remove: :field document update: @@ -61,71 +61,212 @@ db.collection.findAndModify() :ref:`update operators ` or ``field: value`` specifications to modify the selected document. - .. code-block:: javascript - - update: { } - :field boolean new: Optional. When ``true``, returns the modified document rather - than the original. The :dbcommand:`findAndModify` method - ignores the ``new`` option for ``remove`` operations. The - default is ``false``. - - .. code-block:: javascript + than the original. The + :method:`~db.collection.findAndModify()` method ignores the + ``new`` option for ``remove`` operations. The default is + ``false``. - new: + :field document fields: - :field document fields: - - Optional. A subset of fields to return. + Optional. A subset of fields to return. The ``fields`` + document specifies an inclusion of a field with ``1``, as in + the following: .. code-block:: javascript + + fields: { : 1, : 1, ... } + + See :ref:`projection `. - fields: { field1: , field2: ... } + :field boolean upsert: - :field boolean upsert: - Optional. Used in conjunction with the ``update`` field. When - ``true``, :dbcommand:`findAndModify` creates a new document - if the ``query`` returns no documents. The default is - ``false``. In version 2.2, the :dbcommand:`findAndModify` - command returns ``null`` when ``upsert`` is ``true``. + ``true``, :method:`~db.collection.findAndModify()` creates a + new document if the ``query`` returns no documents. The + default is ``false``. - .. code-block:: javascript + The :method:`~db.collection.findAndModify()` method returns either: - upsert: + - the pre-modification document or, - Consider the following example: + - if the ``new: true`` option is set, the modified document. - .. code-block:: javascript + .. note:: + + - If no document is found for the ``update`` or ``remove``, the + the method returns ``null``. + + - If no document is found for an ``upsert``, which means the + command performs an insert, and ``new`` is ``false``, **and** + the ``sort`` option is **NOT** specified, the method returns + ``null``. + + .. versionchanged:: 2.2 + Previously returned an empty document ``{}``. See :ref:`the + 2.2 release notes <2.2-findandmodify-returns-null>` for more + information. + + - If no document is found for an ``upsert``, which means the + command performs an insert, and ``new`` is ``false``, **and** a + ``sort`` option is specified, the method returns an empty + document ``{}``. + + Consider the following examples: + + - The following method updates an existing document in the people + collection where the document matches the query criteria: + + .. code-block:: javascript + + db.people.findAndModify( { + query: { name: "Tom", state: "active", rating: { $gt: 10 } }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } } + } ) + + This method performs the following actions: + + #. The ``query`` finds a document in the ``people`` collection + where the ``name`` field has the value ``Tom``, the ``state`` + field has the value ``active`` and the ``rating`` field has a + value :operator:`greater than <$gt>` 10. + + #. The ``sort`` orders the results of the query in ascending order. + If multiple documents meet the ``query`` condition, the method + will select for modification the first document as ordered by + this ``sort``. + + #. The update :operator:`increments <$inc>` the value of the + ``score`` field by 1. + + #. The method returns the original (i.e. pre-modification) document + selected for this update: - db.people.findAndModify( { - query: { name: "Tom", state: "active", rating: { $gt: 10 } }, - sort: { rating: 1 }, - update: { $inc: { score: 1 } } - } ); + .. code-block:: javascript - This command performs the following actions: + { + "_id" : ObjectId("50f1e2c99beb36a0f45c6453"), + "name" : "Tom", + "state" : "active", + "rating" : 100, + "score" : 5 + } + + To return the modified document, add the ``new:true`` option to + the method. + + If no document matched the ``query`` condition, the method + returns ``null``: - #. The ``query`` finds a document in the ``people`` collection where - the ``name`` field has the value ``Tom``, the ``state`` field has - the value ``active`` and the ``rating`` field has a value - :operator:`greater than <$gt>` 10. + .. code-block:: javascript + + null + + - The following method includes the ``upsert: true`` option to + insert a new document if no document matches the ``query`` + condition: + + .. code-block:: javascript + + db.people.findAndModify( { + query: { name: "Gus", state: "active", rating: 100 }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } }, + upsert: true + } ) + + If the method does **not** find a matching document, the method + performs an upsert. Because the method included the ``sort`` + option, it returns an empty document ``{ }`` as the original + (pre-modification) document: + + .. code-block:: javascript + + { } + + If the method did **not** include a ``sort`` option, the method returns + ``null``. + + .. code-block:: javascript + + null + + - The following method includes both the ``upsert: true`` option and + the ``new:true`` option to return the newly inserted document if a + document matching the ``query`` is not found: + + .. code-block:: none + + db.people.findAndModify( { + query: { name: "Pascal", state: "active", rating: 25 }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } }, + upsert: true, + new: true + } + ) + + The method returns the newly inserted document: + + .. code-block:: javascript + + { + "_id" : ObjectId("50f49ad6444c11ac2448a5d6"), + "name" : "Pascal", + "rating" : 25, + "score" : 1, + "state" : "active" + } + + 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 insert the same document. + + Consider an example where no document with the name ``Andy`` exists + and multiple clients issue the following command: + + .. code-block:: javascript + + db.people.findAndModify( + { + query: { name: "Andy" }, + sort: { rating: 1 }, + update: { $inc: { score: 1 } }, + upsert: true + } + ) + + If all the 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 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: - #. The ``sort`` orders the results of the query in ascending order. + - Exactly one :method:`~db.collection.findAndModify()` would + successfully insert a new document. - #. The update :operator:`increments <$inc>` the value of the - ``score`` field by 1. + - Zero or more :method:`~db.collection.findAndModify()` methods + would update the newly inserted document. - #. The command returns the original unmodified document - selected for this update. + - Zero or more :method:`~db.collection.findAndModify()` methods + would 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. .. warning:: - When using :dbcommand:`findAndModify` in a :term:`sharded - ` environment, the ``query`` must contain the - :term:`shard key` for all operations against the shard - cluster. :dbcommand:`findAndModify` operations issued against - :program:`mongos` instances for non-sharded collections function - normally. + - When using :dbcommand:`findAndModify` in a :term:`sharded + ` environment, the ``query`` must contain the + :term:`shard key` for all operations against the shard cluster. + :dbcommand:`findAndModify` operations issued against + :program:`mongos` instances for non-sharded collections + function normally. diff --git a/source/tutorial/create-an-auto-incrementing-field.txt b/source/tutorial/create-an-auto-incrementing-field.txt index 09d1537b3a6..0c63473948c 100644 --- a/source/tutorial/create-an-auto-incrementing-field.txt +++ b/source/tutorial/create-an-auto-incrementing-field.txt @@ -40,7 +40,7 @@ contains the last value of the sequence. .. code-block:: javascript - db.counters.insert( + db.counters.insert( { _id: "userid", seq: 0 @@ -57,12 +57,12 @@ contains the last value of the sequence. function getNextSequence(name) { var ret = db.counters.findAndModify( { - query: { _id: name }, - update: { $inc: { seq: 1 } }, + query: { _id: name }, + update: { $inc: { seq: 1 } }, new: true } ); - + return ret.seq; } @@ -73,15 +73,15 @@ contains the last value of the sequence. db.users.insert( { - _id: getNextSequence("userid"), - name: "Sarah C." + _id: getNextSequence("userid"), + name: "Sarah C." } ) db.users.insert( { - _id: getNextSequence("userid"), - name: "Bob D." + _id: getNextSequence("userid"), + name: "Bob D." } ) @@ -97,13 +97,61 @@ contains the last value of the sequence. { _id : 1, - name : "Sarah C." + name : "Sarah C." } - { - _id : 2, - name : "Bob D." + { + _id : 2, + name : "Bob D." } +.. note:: + + 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 insert the same document. + + In the ``counters`` collection example, the query field is the + ``_id`` field, which always has a unique index. Consider that the + :method:`~db.collection.findAndModify()` includes the ``upsert: + true`` option, as in the following modified example: + + .. code-block:: javascript + :emphasize-lines: 7 + + function getNextSequence(name) { + var ret = db.counters.findAndModify( + { + query: { _id: name }, + update: { $inc: { seq: 1 } }, + new: true, + upsert: true + } + ); + + return ret.seq; + } + + If multiple clients were to invoke the ``getNextSequence()`` method + with the same ``name`` parameter, then the methods would observe one + of the following behaviors: + + - Exactly one :method:`~db.collection.findAndModify()` would + successfully insert a new document. + + - Zero or more :method:`~db.collection.findAndModify()` methods + would update the newly inserted document. + + - Zero or more :method:`~db.collection.findAndModify()` methods + would fail when they attempted to insert a duplicate. + + If the method fails due to a unique index constraint violation, + retry the method. Absent a delete of the document, the retry + should not fail. + .. _auto-increment-optimistic-loop: Optimistic Loop