Skip to content

Commit 14d586e

Browse files
author
Sam Kleinman
committed
merge: DOCS-683
2 parents ec6f87d + ff1959f commit 14d586e

File tree

6 files changed

+130
-7
lines changed

6 files changed

+130
-7
lines changed

source/reference/method/db.collection.findAndModify.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ db.collection.findAndModify()
111111
#. The ``query`` finds a document in the ``people`` collection where
112112
the ``name`` field has the value ``Tom``, the ``state`` field has
113113
the value ``active`` and the ``rating`` field has a value
114-
: operator:`greater than <$gt>` 10.
114+
:operator:`greater than <$gt>` 10.
115115

116116
#. The ``sort`` orders the results of the query in ascending order.
117117

source/reference/method/db.collection.remove.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ db.collection.remove()
7676
write operations to that collection. For an unsharded collection,
7777
you have the option to override this behavior with the
7878
:operator:`$atomic` isolation operator, effectively isolating the
79-
delete operation and blocking all other operations during the
79+
delete operation and blocking other write operations during the
8080
delete. To isolate the query, include ``$atomic: 1`` in the
8181
``query`` parameter as in the following example:
8282

source/reference/method/db.collection.update.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,15 @@ db.collection.update()
106106
In version 2.2 of the :program:`mongo` shell, you may also
107107
specify ``multi`` in the ``options`` parameter.
108108

109+
.. note::
110+
111+
The ``multi`` update operation may interleave with other
112+
write operations to that collection. For an unsharded
113+
collection, you have the option to override this behavior
114+
with the :operator:`$atomic` isolation operator,
115+
effectively isolating the update operation and blocking
116+
other write operations during the update. See the
117+
:doc:`isolation operator </reference/operator/atomic>`.
109118

110119
Although the update operation may apply mostly to updating the
111120
values of the fields, the :method:`update()

source/reference/operator/atomic.txt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@ $atomic
66

77
.. operator:: $atomic
88

9-
In multi-update mode, it's possible to specify an
10-
:operator:`$atomic` "operator" that allows you to **isolate** some
11-
updates from each other within this operation. Consider the
12-
following example:
9+
:operator:`$atomic` isolation operator **isolates** a write
10+
operation that affect multiple documents from other write operations.
11+
12+
.. note::
13+
14+
The :operator:`$atomic` isolation operator does **not** mean
15+
"all-or-nothing" atomicity to the write operation.
16+
17+
Consider the following example:
1318

1419
.. code-block:: javascript
1520

16-
db.foo.update( { field1 : 1 , $atomic : 1 }, { $inc : { field2 : 1 } } , false , true )
21+
db.foo.update( { field1 : 1 , $atomic : 1 }, { $inc : { field2 : 1 } } , { multi: true } )
1722

1823
Without the :operator:`$atomic` operator, multi-updates will allow
1924
other operations to interleave with this updates. If these

source/tutorial.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Development Patterns
3737
:maxdepth: 1
3838

3939
tutorial/perform-two-phase-commits
40+
tutorial/isolate-sequence-of-operations
4041
tutorial/enforce-unique-keys-for-sharded-collections
4142
tutorial/aggregation-examples
4243

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
==============================
2+
Isolate Sequence of Operations
3+
==============================
4+
5+
.. default-domain:: mongodb
6+
7+
Background
8+
----------
9+
10+
Write operations are atomic on the level of a single document: no
11+
single write operation can atomically affect more than one document or
12+
more than one collection.
13+
14+
When a single write operation modifies multiple documents, the
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-document
18+
*within* the single record.
19+
20+
No other operations are atomic; however, you can *isolate* a
21+
single write operation that affects multiple documents using the
22+
:doc:`isolation operator </reference/operator/atomic>`.
23+
24+
Additionally, the following patterns can manage a sequence of
25+
operations:
26+
27+
- :method:`findAndModify() <db.collection.findAndModify()>`
28+
29+
- :ref:`tutorial-atomic-update-if-current`
30+
31+
- :doc:`/tutorial/perform-two-phase-commits`
32+
33+
- :method:`ensureIndex() <db.collection.ensureIndex()>` to create a
34+
``unique`` index on a field
35+
36+
.. _tutorial-atomic-update-if-current:
37+
38+
Update if Current
39+
-----------------
40+
41+
The "Update if Current" pattern queries a document, locally modifies
42+
various fields of the document, and tries to update the fields of a
43+
document *if* the fields have not changed in the collection since the
44+
query.
45+
46+
Consider the following example which attempts to update the ``qty``
47+
field of a document in the ``products`` collection:
48+
49+
.. code-block:: javascript
50+
51+
var myCollection = db.products;
52+
var myDocument = myCollection.findOne( { sku: 'abc123' } );
53+
54+
if (myDocument) {
55+
56+
var oldQty = myDocument.qty;
57+
58+
if (myDocument.qty < 10) {
59+
myDocument.qty *= 4;
60+
} else if ( myDocument.qty < 20 ) {
61+
myDocument.qty *= 3;
62+
} else {
63+
myDocument.qty *= 2;
64+
}
65+
66+
myCollection.update(
67+
{
68+
_id: myDocument._id,
69+
qty: oldQty
70+
},
71+
{
72+
$set: { qty: myDocument.qty }
73+
}
74+
)
75+
76+
var err = db.getLastErrorObj();
77+
78+
if ( err && err.code ) {
79+
print("unexpected error updating document: " + tojson( err ));
80+
} else if ( err.n == 0 ) {
81+
print("No update: no matching document for { _id: " + myDocument._id + ", qty: " + oldQty + " }")
82+
}
83+
84+
}
85+
86+
Consider the following modifications to the "Update if Current" strategy:
87+
88+
- To generalize the strategy to guarantee that the whole document has
89+
not changed rather than just certain fields, use the entire document in
90+
the query expression.
91+
92+
- Add a version variable that is incremented upon each update operation
93+
to the documents. Use this version variable in the query expression.
94+
95+
- Use :operator:`$set` in the update expression to modify only your
96+
fields and prevent overriding other fields.
97+
98+
.. Add link to :doc:`/tutorial/create-an-auto-increment-field` once that branch is merged since it's a special case
99+
100+
.. Maybe incorporate the blurb: "MongoDB does not
101+
support traditional locking and complex transactions for a number of
102+
reasons: First, in sharded environments, distributed locks could be
103+
expensive and slow. Mongo DB's goal is to be lightweight and fast. We
104+
dislike the concept of deadlocks. We want the system to be simple and
105+
predictable without these sort of surprises. We want Mongo DB to work
106+
well for realtime problems. If an operation may execute which locks
107+
large amounts of data, it might stop some small light queries for an
108+
extended period of time."

0 commit comments

Comments
 (0)