Navigation

Read Isolation, Consistency, and Recency

Isolation Guarantees

Read Uncommitted

Depending on the read concern, clients can see the results of writes before the writes are durable:

  • Regardless of write concern, other clients using "local" or "available" readConcern can see the result of a write operation before the write operation is acknowledged to the issuing client.

    For operations in a multi-document transaction, the data changes made in the transaction are not visible outside the transaction until a transaction commits. However, other clients can see the result at the time of the transaction commit before the commit operation is acknowledged to the issuing client.

  • Clients using "local" or "available" readConcern can read data which may be subsequently rolled back during replica set failovers.

Read uncommitted is the default isolation level and applies to mongod standalone instances as well as to replica sets and sharded clusters.

Read Uncommitted And Single Document Atomicity

Write operations are atomic with respect to a single document; i.e. if a write is updating multiple fields in the document, a read operation will never see the document with only some of the fields updated. However, although a client may not see a partially updated document, read uncommitted means that concurrent read operations may still see the updated document before the changes are made durable.

With a standalone mongod instance, a set of read and write operations to a single document is serializable. With a replica set, a set of read and write operations to a single document is serializable only in the absence of a rollback.

Read Uncommitted And Multiple Document Write

When a single write operation (e.g. db.collection.updateMany()) modifies multiple documents, the modification of each document is atomic, but the operation as a whole is not atomic.

When performing multi-document write operations, whether through a single write operation or multiple write operations, other operations may interleave.

Starting in version 4.0, for situations that require atomicity for updates to multiple documents or consistency between reads to multiple documents, MongoDB provides multi-document transactions for replica sets.

Important

In most cases, multi-document transaction incurs a greater performance cost over single document writes, and the availability of multi-document transaction should not be a replacement for effective schema design. For many scenarios, the denormalized data model (embedded documents and arrays) will continue to be optimal for your data and use cases. That is, for many scenarios, modeling your data appropriately will minimize the need for multi-document transactions.

Without isolating the multi-document write operations, MongoDB exhibits the following behavior:

  1. Non-point-in-time read operations. Suppose a read operation begins at time t1 and starts reading documents. A write operation then commits an update to one of the documents at some later time t2. The reader may see the updated version of the document, and therefore does not see a point-in-time snapshot of the data.
  2. Non-serializable operations. Suppose a read operation reads a document d1 at time t1 and a write operation updates d1 at some later time t3. This introduces a read-write dependency such that, if the operations were to be serialized, the read operation must precede the write operation. But also suppose that the write operation updates document d2 at time t2 and the read operation subsequently reads d2 at some later time t4. This introduces a write-read dependency which would instead require the read operation to come after the write operation in a serializable schedule. There is a dependency cycle which makes serializability impossible.
  3. Reads may miss matching documents that are updated during the course of the read operation.

Cursor Snapshot

MongoDB cursors can return the same document more than once in some situations. As a cursor returns documents other operations may interleave with the query. If some of these operations change the indexed field on the index used by the query; then the cursor will return the same document more than once.

If your collection has a field or fields that are never modified, you can use a unique index on this field or these fields so that the query will return each document no more than once. Query with hint() to explicitly force the query to use that index.

Monotonic Writes

MongoDB provides monotonic write guarantees, by default, for standalone mongod instances and replica set.

For monotonic writes and sharded clusters, see Causal Consistency.

Real Time Order

New in version 3.4.

For read and write operations on the primary, issuing read operations with "linearizable" read concern and write operations with "majority" write concern enables multiple threads to perform reads and writes on a single document as if a single thread performed these operations in real time; that is, the corresponding schedule for these reads and writes is considered linearizable.

Causal Consistency

New in version 3.6.

If an operation logically depends on a preceding operation, there is a causal relationship between the operations. For example, a write operation that deletes all documents based on a specified condition and a subsequent read operation that verifies the delete operation have a causal relationship.

With causally consistent sessions, MongoDB executes causal operations in an order that respect their causal relationships, and clients observe results that are consistent with the causal relationships.

Client Sessions and Causal Consistency Guarantees

To provide causal consistency, MongoDB 3.6 enables causal consistency in client sessions. A causally consistent session denotes that the associated sequence of read operations with "majority" read concern and write operations with "majority" write concern have a causal relationship that is reflected by their ordering. Applications must ensure that only one thread at a time executes these operations in a client session.

For causally related operations:

  1. A client starts a client session.

    Important

    Client sessions only guarantee causal consistency for:

    • Read operations with "majority"; i.e. the return data has been acknowledged by a majority of the replica set members and is durable.
    • Write operations with "majority" write concern; i.e. the write operations that request acknowledgement that the operation has been applied to a majority of the replica set’s voting members.

    For more information on causal consistency and various read and write concerns, see Causal Consistency and Read and Write Concerns.

  2. As the client issues a sequence of read with "majority" read concern and write operations (with "majority" write concern), the client includes the session information with each operation.

  3. For each read operation with "majority" read concern and write operation with "majority" write concern associated with the session, MongoDB returns the operation time and the cluster time, even if the operation errors. The client session keeps track of the operation time and the cluster time.

    Note

    MongoDB does not return the operation time and the cluster time for unacknowledged (w: 0) write operations. Unacknowledged writes do not imply any causal relationship.

    Although, MongoDB returns the operation time and the cluster time for read operations and acknowledged write operations in a client session, only the read operations with "majority" read concern and write operations with "majority" write concern can guarantee causal consistency. For details, see Causal Consistency and Read and Write Concerns.

  4. The associated client session tracks these two time fields.

    Note

    Operations can be causally consistent across different sessions. MongoDB drivers and the mongo shell provide the methods to advance the operation time and the cluster time for a client session. So, a client can advance the cluster time and the operation time of one client session to be consistent with the operations of another client session.

Causal Consistency Guarantees

The following table lists the causal consistency guarantees provided by causally consistent sessions for read operations with "majority" read concern and write operations with "majority" write concern.

Guarantees Description
Read your writes Read operations reflect the results of write operations that precede them.
Monotonic reads

Read operations do not return results that correspond to an earlier state of the data than a preceding read operation.

For example, if in a session:

  • write1 precedes write2,
  • read1 precedes read2, and
  • read1 returns results that reflect write2

then read2 cannot return results of write1.

Monotonic writes

Write operations that must precede other writes are executed before those other writes.

For example, if write1 must precedes write2 in a session, the state of the data at the time of write2 must reflect the state of the data post write1. Other writes can interleave between write1 and write write2, but write2 cannot occur before write1.

Writes follow reads Write operations that must occur after read operations are executed after those read operations. That is, the state of the data at the time of the write must incorporate the state of the data of the preceding read operations.

Read Preference

These guarantees hold across all members of the MongoDB deployment. For example, if, in a causally consistent session, you issue a write with "majority" write concern followed by a read that reads from a secondary (i.e. read preference <secondary>) with "majority" read concern, the read operation will reflect the state of the database after the write operation.

Isolation

Operations within a causally consistent session are not isolated from operations outside the session. If a concurrent write operation interleaves between the session’s write and read operations, the session’s read operation may return results that reflect a write operation that occurred after the session’s write operation.

Feature Compatibility Version

The featureCompatibilityVersion (fCV) must be set to “3.6” or greater. To check the fCV, run the following command:

db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

For more information, see View FeatureCompatibilityVersion and setFeatureCompatibilityVersion.

MongoDB Drivers

Clients require MongoDB drivers updated for MongoDB 3.6 or later:

Java 3.6+

Python 3.6+

C 1.9+

C# 2.5+

Node 3.0+

Ruby 2.5+

Perl 2.0+

PHPC 1.4+

Scala 2.2+

Examples

Important

Causally consistent sessions can only guarantee causal consistency for reads with "majority" read concern and writes with "majority" write concern.

Consider a collection items that maintains the current and historical data for various items. Only the historical data has a non-null end date. If the sku value for an item changes, the document with the old sku value needs to be updated with the end date, after which the new document is inserted with the current sku value. The client can use a causally consistent session to ensure that the update occurs before the insert.

    with client.start_session(causal_consistency=True) as s1:
        current_date = datetime.datetime.today()
        items = client.get_database(
            'test', read_concern=ReadConcern('majority'),
            write_concern=WriteConcern('majority', wtimeout=1000)).items
        items.update_one(
            {'sku': "111", 'end': None},
            {'$set': {'end': current_date}}, session=s1)
        items.insert_one(
            {'sku': "nuts-111", 'name': "Pecans",
             'start': current_date}, session=s1)
    
    $items = $client->selectDatabase(
        'test',
        [
            'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::MAJORITY),
            'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000),
        ]
    )->items;
    
    $s1 = $client->startSession(
        [ 'causalConsistency' => true ]
    );
    
    $currentDate = new \MongoDB\BSON\UTCDateTime();
    
    $items->updateOne(
        [ 'sku' => '111', 'end' => [ '$exists' => false ] ],
        [ '$set' => [ 'end' => $currentDate ] ],
        [ 'session' => $s1 ]
    );
    $items->insertOne(
        [ 'sku' => '111-nuts', 'name' => 'Pecans', 'start' => $currentDate ],
        [ 'session' => $s1 ]
    );
    

    If another client needs to read all current sku values, you can advance the cluster time and the operation time to that of the other session to ensure that this client is causally consistent with the other session and read after the two writes:

    with client.start_session(causal_consistency=True) as s2:
        s2.advance_cluster_time(s1.cluster_time)
        s2.advance_operation_time(s1.operation_time)
    
        items = client.get_database(
            'test', read_preference=ReadPreference.SECONDARY,
            read_concern=ReadConcern('majority'),
            write_concern=WriteConcern('majority', wtimeout=1000)).items
        for item in items.find({'end': None}, session=s2):
            print(item)
    
    $s2 = $client->startSession(
        [ 'causalConsistency' => true ]
    );
    $s2->advanceClusterTime($s1->getClusterTime());
    $s2->advanceOperationTime($s1->getOperationTime());
    
    $items = $client->selectDatabase(
        'test',
        [
            'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::RP_SECONDARY),
            'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::MAJORITY),
            'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000)
        ]
    )->items;
    
    $result = $items->find(
        [ 'end' => [ '$exists' => false ] ],
        [ 'session' => $s2 ]
    );
    foreach ($result as $item) {
        var_dump($item);
    }
    

    Limitations

    The following operations that build in-memory structures are not causally consistent:

    Operation Notes
    collStats  
    $collStats with latencyStats option.  
    $currentOp Returns an error if the operation is associated with a causally consistent client session.
    dbStats  
    getMore Returns an error if the operation is associated with a causally consistent client session.
    $indexStats  
    ping Returns an error if the operation is associated with a causally consistent client session.
    serverStatus Returns an error if the operation is associated with a causally consistent client session.
    createIndexes with background: true option; i.e. background index builds