@@ -13,109 +13,48 @@ more than one collection.
13
13
14
14
When a single write operation modifies multiple documents, the
15
15
operation as a whole is not atomic, and other operations may
16
- interleave. The modification of a single document, or record, is always
17
- atomic, even if the write operation modifies multiple sub-documents
18
- *within* the single record.
16
+ interleave. The modification of a single document is always atomic, even if
17
+ the write operation modifies multiple sub-documents *within* the single record.
19
18
20
- No other operations are atomic; however , you can *isolate* a
19
+ No other operations are atomic. However , you can *isolate* a
21
20
single write operation that affects multiple documents using the
22
- :doc:`isolation operator </reference/operator/update/isolated>`.
21
+ :doc:`isolation operator </reference/operator/update/isolated>`. Using this
22
+ operator, you can update a set of documents without allowing other processes
23
+ to update in between your writes.
23
24
24
- This document describes one method of updating documents *only* if the
25
- local copy of the document reflects the current state of the document
26
- in the database. In addition the following methods provide a way to
27
- manage isolated sequences of operations:
25
+ It is important to understand that this is *not* true atomicity, because a
26
+ failed write will not roll back the preceding writes. Additionally, this
27
+ operator does *not* work on sharded clusters.
28
28
29
- - the :method:`~db.collection.findAndModify()`
30
- provides an isolated update and return operation.
29
+ Approaches
30
+ ----------
31
31
32
- - :doc:`/tutorial/perform-two-phase-commits`
32
+ ``findAndModify()``
33
+ ~~~~~~~~~~~~~~~~~~~
33
34
34
- - Create a :ref:`unique index <index-type-unique>`, to ensure that a
35
- key doesn't exist when you insert it.
35
+ The :method:`~db.collection.findAndModify()` method provides an isolated
36
+ update-and-return operation. This allows you to update a document and get back
37
+ the updated state, without having to worry about another process having mutated
38
+ it.
36
39
37
- .. _tutorial-atomic-update-if-current:
40
+ Two Phase Commit
41
+ ~~~~~~~~~~~~~~~~
38
42
39
- Update if Current
40
- -----------------
41
-
42
- In this pattern, you will:
43
-
44
- - query for a document,
45
-
46
- - modify the fields in that document
47
-
48
- - and update the fields of a document *only if* the fields have not
49
- changed in the collection since the query.
50
-
51
- Consider the following example in JavaScript which attempts to update
52
- the ``qty`` field of a document in the ``products`` collection:
53
-
54
- .. versionchanged:: 2.6
55
- The :method:`db.collection.update()` method now returns a
56
- :method:`WriteResult()` object that contains the status of
57
- the operation. Previous versions required an extra
58
- :method:`db.getLastErrorObj()` method call.
59
-
60
- .. code-block:: javascript
61
-
62
- var myCollection = db.products;
63
- var myDocument = myCollection.findOne( { sku: 'abc123' } );
43
+ :doc:`Two Phase Commit </tutorial/perform-two-phase-commits>` is a general
44
+ protocol for multi-document transactions that you may implement in your
45
+ application logic.
64
46
65
- if (myDocument) {
47
+ Unique Indexes
48
+ ~~~~~~~~~~~~~~
66
49
67
- var oldQty = myDocument.qty;
50
+ Create a :ref:`unique index <index-type-unique>` to ensure that each document
51
+ has a distinct value for a specific field. In situations where you assign a
52
+ value that does not already exist in a collection, this prevents a second
53
+ process from assigning the same value elsewhere at the same time.
68
54
69
- if (myDocument.qty < 10) {
70
- myDocument.qty *= 4;
71
- } else if ( myDocument.qty < 20 ) {
72
- myDocument.qty *= 3;
73
- } else {
74
- myDocument.qty *= 2;
75
- }
76
-
77
- var results = myCollection.update(
78
- {
79
- _id: myDocument._id,
80
- qty: oldQty
81
- },
82
- {
83
- $set: { qty: myDocument.qty }
84
- }
85
- );
86
-
87
- if ( results.hasWriteError() ) {
88
- print("unexpected error updating document: " + tojson( results ));
89
- } else if ( results.nMatched == 0 ) {
90
- print("No update: no matching document for { _id: " + myDocument._id + ", qty: " + oldQty + " }")
91
- }
92
-
93
- }
94
-
95
- Your application may require some modifications of this pattern, such
96
- as:
97
-
98
- - Use the entire document as the query in the
99
- :method:`~db.collection.update()` operation, to generalize the
100
- operation and guarantee that the original document was not modified,
101
- rather than ensuring that as single field was not changed.
102
-
103
- - Add a version variable to the document that applications increment
104
- upon each update operation to the documents. Use this version
105
- variable in the query expression. You must be able to ensure that
106
- *all* clients that connect to your database obey this constraint.
107
-
108
- - Use :update:`$set` in the update expression to modify only your
109
- fields and prevent overriding other fields.
110
-
111
- - Use one of the methods described in :doc:`/tutorial/create-an-auto-incrementing-field`.
55
+ Update if Current
56
+ ~~~~~~~~~~~~~~~~~
112
57
113
- .. Maybe incorporate the blurb: "MongoDB does not
114
- support traditional locking and complex transactions for a number of
115
- reasons: First, in sharded environments, distributed locks could be
116
- expensive and slow. MongoDB's goal is to be lightweight and fast. We
117
- dislike the concept of deadlocks. We want the system to be simple and
118
- predictable without these sort of surprises. We want MongoDB to work
119
- well for realtime problems. If an operation may execute which locks
120
- large amounts of data, it might stop some small light queries for an
121
- extended period of time."
58
+ :doc:`Update if Current </tutorial/update-if-current>` is a pattern for
59
+ changing a document without potentially overwriting the changes of other
60
+ processes.
0 commit comments