HomeLearnHow-to

Set Global Read and Write Concerns in MongoDB 4.4

Published: Jun 26, 2020

  • MongoDB
  • Atlas
  • ...

By Ado Kukic

Share

MongoDB is very flexible when it comes to both reading and writing data. When it comes to writing data, a MongoDB write concern allows you to set the level of acknowledgment for a desired write operation. Likewise, the read concern allows you to control the consistency and isolation properties of the data read from your replica sets. Finding the right values for the read and write concerns is pivotal as your application evolves and with the latest release of MongoDB adding global read isolation and write durability defaults is now possible.

MongoDB 4.4 is available in beta right now. You can try it out in MongoDB Atlas or download the development release. In this post, we are going to look at how we can set our read isolation and write durability defaults globally and also how we can override these global settings on a per client or per operation basis when needed.

#Prerequisites

For this tutorial you'll need:

Setting global read and write concerns is currently unavailable on MongoDB Atlas. If you wish to follow along with this tutorial, you'll need your own instance of MongoDB 4.4 installed.

#Read and Write Concerns

Before we get into how we can set these features globally, let's quickly examine what it is they actually do, what benefits they provide, and why we should even care.

We'll start with the MongoDB write concern functionality. By default, when you send a write operation to a MongoDB database, it has a write concern of w:1. What this means is that the write operation will be acknowledged as successful when the primary in a replica set has successfully executed the write operation.

Let's assume you're working with a 3-node replicate set, which is the default when you create a free MongoDB Atlas cluster. Sending a write command such as db.collection('test').insertOne({name:"Ado"}) will be deemed successful when the primary has acknowledged the write. This ensures that the data doesn't violate any database constraints and has successfully been written to the database in memory. We can improve this write concern durability, by increasing the number of nodes we want to acknowledge the write.

Instead of w:1, let's say we set it to w:2. Now when we send a write operation to the database, we wouldn't hear back until both the primary, and one of the two secondary nodes acknowledged the write operation was successful. Likewise, we could also set the acknowledgement value to 0, i.e w:0, and in this instance we wouldn't ask for acknowledgement at all. I wouldn't recommend using w:0 for any important data, but in some instances it can be a valid option. Finally, if we had a three member replica set and we set the w value to 3, i.e w:3, now the primary and both of the secondary nodes would need to acknowledge the write. I wouldn't recommend this approach either, because if one of the secondary members become unavailable, we wouldn't be able to acknowledge write operations, and our system would no longer be highly available.

Additionally, when it comes to write concern, we aren't limited to setting a numeric value. We can set the value of w to "majority" for example, which will wait for the write operation to propagate to a majority of the nodes or even write our own custom write concern.

MongoDB read concern allows you to control the consistency and isolation properties of the data read from replica sets and replica set shards. Essentially what this means is that when you send a read operation to the database such as a db.collection.find(), you can specify how durable the data that is returned must be. Note that read concern should not be confused with read preference, which specifies which member of a replica set you want to read from.

There are multiple levels of read concern including local, available, majority, linearizable, and snapshot. Each level is complex enough that it can be an article itself, but the general idea is similar to that of the write concern. Setting a read concern level will allow you to control the type of data read. Defaults for read concerns can vary and you can find what default is applied when here. Default read concern reads the most recent data, rather than data that's been majority committed.

Through the effective use of write concerns and read concerns, you can adjust the level of consistency and availability defaults as appropriate for your application.

#Setting Global Read and Write Concerns

So now that we know a bit more about why these features exist and how they work, let's see how we can change the defaults globally. In MongoDB 4.4, we can use the db.adminCommand() to configure our isolation and durability defaults.

Setting global read and write concerns is currently unavailable on MongoDB Atlas. If you wish to follow along with this tutorial, you'll need your own instance of MongoDB 4.4 installed.

We'll use the db.adminCommand() to set a default read and write concern of majority. In the MongoDB shell, execute the following command:

1
2
3
4
5
db.adminCommand({ setDefaultRWConcern: 1, defaultReadConcern: { level : "majority" }, defaultWriteConcern: { w: "majority" } })

Note that to execute this command you need to have a replica set and the command will need to be sent to the primary node. Additionally, if you have a sharded cluster, the command will need to be run on the mongos. If you have a standalone node, you'll get an error. The final requirement to be able to execute the setDefaultRWConcern command is having the correct privilege.

When setting default read and write concerns, you don't have to set both a default read concern and a default write concern, you are allowed to set only a default read concern or a default write concern as you see fit. For example, say we only wanted to set a default write concern, it would look something like this:

1
2
3
4
db.adminCommand({ setDefaultRWConcern: 1, defaultWriteConcern: { w: 2 } })

The above command would set just a default write concern of 2, meaning that the write would succeed when the primary and one secondary node acknowledged the write.

When it comes to default write concerns, in addition to specifying the acknowledgment, you can also set a wtimeout period for how long an operation has to wait for an acknowledgement. To set this we can do this:

1
2
3
4
db.adminCommand({ setDefaultRWConcern: 1, defaultWriteConcern: { w: 2, wtimeout: 5000 } })

This will set a timeout of 5000ms so if we don't get an acknowledgement within 5 seconds, the write operation will return an writeConcern timeout error.

To unset either a default read or write concern, you can simply pass into it an empty object.

1
2
3
4
5
db.adminCommand({ setDefaultRWConcern: 1, defaultReadConcern: { }, defaultWriteConcern: { } })

This will return the read concern and the write concern to their MongoDB defaults. You can also easily check and see what defaults are currently set for your global read and write concerns using the getDefaultRWConcern command. When you run this command against the admin database like so:

1
2
3
db.adminCommand({ getDefaultRWConcern: 1 })

You will get a response like the one below showing you your global settings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{ "defaultWriteConcern" : { "w" : "majority" }, "defaultReadConcern" : { "level" : "majority" }, "updateOpTime" : Timestamp(1586290895, 1), "updateWallClockTime" : ISODate("2020-04-07T20:21:41.849Z"), "localUpdateWallClockTime" : ISODate("2020-04-07T20:21:41.862Z"), "ok" : 1, "$clusterTime" : { ... } "operationTime" : Timestamp(1586290925, 1) }

In the next section, we'll take a look at how we can override these global settings when needed.

#Overriding Global Read and Write Concerns

MongoDB is a very flexible database. The default read and write concerns allow you to set reasonable defaults for how clients interact with your database cluster-wide, but as your application evolves a specific client may need a different read isolation or write durability default. This can be accomplished using any of the MongoDB drivers.

We can override read and write concerns at:

  • the client connection layer when connecting to the MongoDB database,
  • the database level,
  • the collection level,
  • an individual operation or query.

However, note that MongoDB transactions can span multiple databases and collections, and since all operations within a transaction must use the same write concern, transactions have their own hierarchy of:

  • the client connection layer,
  • the session level,
  • the transaction level.

A diagram showing this inheritance is presented below to help you understand what read and write concern takes precedence when multiple are declared:

Read and Write Concerns Diagram

We'll take a look at a couple of examples where we override the read and write concerns. For our examples we'll use the Node.js Driver.

Let's see an example of how we would overwrite our read and write concerns in our Node.js application. The first example we'll look at is how to override read and write concerns at the database level. To do this our code will look like this:

1
2
3
4
5
6
7
8
9
const MongoClient = require('mongodb').MongoClient; const uri = "{YOUR-CONNECTION-STRING}"; const client = new MongoClient(uri, { useNewUrlParser: true }); client.connect(err => { const options = {w:"majority", readConcern: {level: "majority"}}; const db = client.db("test", options); });

When we specify the database we want to connect to, in this case the database is called test, we also pass an options object with the read and write concerns we wish to use. For our first example, we are using the majority concern for both read and write operations.

If we already set defaults globally, then overriding in this way may not make sense, but we may still run into a situation where we want a specific collection to execute read and write operations at a specific read or write concern. Let's declare a collection with a majority write concern and a read concern "majority".

1
2
3
const options = {w:"majority", readConcern: {level: "majority"}}; const collection = db.collection('documents', options);

Likewise we can even scope it down to a specific operation. In the following example we'll use the majority read concern for just one specific query.

1
2
3
const collection = db.collection('documents'); collection.insertOne({name:"Ado Kukic"}, {w:"majority", wtimeout: 5000})

The code above will execute a write query and try to insert a document that has one field titled name. For the query to be successful, the write operation will have to be acknowledged by the primary and one secondary, assuming we have a three member replica set.

Being able to set the default read and write concerns is important to providing developers the ability to set defaults that make sense for their use case, but also the flexibility to easily override those defaults when needed.

#Conclusion

Global read or write concerns allow developers to set default read isolation and write durability defaults for their database cluster-wide. As your application evolves, you are able to override the global read and write concerns at the client level ensuring you have flexibility when you need it and customized defaults when you don't. It is available in MongoDB 4.4, which is available in beta today.

Safe Harbor Statement

The development, release, and timing of any features or functionality described for MongoDB products remains at MongoDB's sole discretion. This information is merely intended to outline our general product direction and it should not be relied on in making a purchasing decision nor is this a commitment, promise or legal obligation to deliver any material, code, or functionality. Except as required by law, we undertake no obligation to update any forward-looking statements to reflect events or circumstances after the date of such statements.

MongoDB Icon
  • Developer Hub
  • Documentation
  • University
  • Community Forums

© MongoDB, Inc.