Overview
In this guide, you can learn how to configure write concern, read concern, and read preference options to modify the way that the Kotlin driver runs read and write operations on replica sets.
Read and Write Settings Precedence
You can set write concern, read concern, and read preference options at the following levels:
Client, which sets the default for all operation executions unless overridden
Transaction
Database
Collection
This list also indicates the increasing order of precedence of the option settings. For example, if you set a read concern for a transaction, it will override the read concern settings inherited from the client.
Write concern, read concern, and read preference options allow you to customize the causal consistency and availability of the data in your replica sets. To see a full list of these options, see the following guides in the MongoDB server manual:
Configure Read and Write Operations
You can control how the driver routes read operations among replica set members by setting a read preference. You can also control how the driver waits for acknowledgment of read and write operations on a replica set by setting read and write concerns.
The following sections show how to configure these read and write settings at various levels.
Client Configuration
This example shows how to set the read preference, read concern, and write concern of a MongoClient instance by passing a MongoClientSettings instance to the MongoClient.create() method. The code configures the following settings:
secondaryread preference: Read operations retrieve data from secondary replica set members.LOCALread concern: Read operations return the instance's most recent data without guaranteeing that the data has been written to a majority of the replica set members.W2write concern: The primary replica set member and one secondary member must acknowledge the write operation.
val settings = MongoClientSettings.builder() .applyConnectionString(ConnectionString("mongodb://localhost:27017/")) .readPreference(ReadPreference.secondary()) .readConcern(ReadConcern.LOCAL) .writeConcern(WriteConcern.W2) .build() val mongoClient = MongoClient.create(settings)
Alternatively, you can specify the read and write settings in the connection URI, which is passed as a parameter to the MongoClient.create() method:
val uri = "mongodb://localhost:27017/?readPreference=secondary&w=2&readConcernLevel=local" val uriClient = MongoClient.create(uri)
Transaction Configuration
This example shows how to set the read preference, read concern, and write concern of a transaction by passing a TransactionOptions instance to the startTransaction() method. Transactions run within sessions, which are groupings of related read or write operations that you intend to run sequentially.
Tip
To learn more about sessions, see Server Sessions in the MongoDB server manual.
The example configures the following settings:
primaryread preference: Read operations retrieve data from the primary replica set member.MAJORITYread concern: Read operations return the instance's most recent data that has been written to a majority of replica set members.W1write concern: The primary replica set member must acknowledge the write operation.
mongoClient.startSession().use { session -> try { // Sets transaction read and write settings val txnOptions = TransactionOptions.builder() .readPreference(ReadPreference.primary()) .readConcern(ReadConcern.MAJORITY) .writeConcern(WriteConcern.W1) .build() runBlocking { session.startTransaction(txnOptions) // Specify transaction operations here session.commitTransaction() } } catch (e: Exception) { println("Transaction failed: ${e.message}") } }
Database Configuration
This example shows how to set the read preference, read concern, and write concern of a database called test_database by chaining setter methods to the getDatabase() method. The code configures the following settings:
primaryPreferredread preference: Read operations retrieve data from the primary replica set member, or secondary members if the primary is unavailable.AVAILABLEread concern: Read operations return the instance's most recent data without guaranteeing that the data has been written to a majority of the replica set members.MAJORITYwrite concern: The majority of all replica set members must acknowledge the write operation.
val database = mongoClient.getDatabase("test_database") .withReadPreference(ReadPreference.primaryPreferred()) .withReadConcern(ReadConcern.AVAILABLE) .withWriteConcern(WriteConcern.MAJORITY)
Collection Configuration
This example shows how to set the read preference, read concern, and write concern of a collection called test_collection by chaining setter methods to the getCollection() method. The code configures the following settings:
secondaryPreferredread preference: Read operations retrieve data from secondary replica set members, or the primary members if no secondary members are available.AVAILABLEread concern: Read operations return the instance's most recent data without guaranteeing that the data has been written to a majority of the replica set members.UNACKNOWLEDGEDwrite concern: Replica set members do not need to acknowledge the write operation.
val collection = database.getCollection<Document>("test_collection") .withReadPreference(ReadPreference.secondaryPreferred()) .withReadConcern(ReadConcern.AVAILABLE) .withWriteConcern(WriteConcern.UNACKNOWLEDGED)
Advanced Read Configurations
The following sections describe ways to further customize how the Kotlin driver routes read operations.
Sharded Clusters
You can specify a read preference when connecting to a sharded cluster. MongoDB uses sharding to divide datasets by key ranges and distribute data across multiple database instances. A sharded cluster, or the set of nodes in a sharded deployment, includes the following components:
Shard: A replica set that contains a subset of the sharded data.
Mongos: A query router that provides an interface between your application and the sharded cluster.
Config servers: Servers that store the cluster's configuration settings and metadata.
Tip
To learn more about sharded clusters, see Sharding in the MongoDB server manual.
When reading from the replica set shards, mongos applies your specified read preference. The read preference is re-evaluated for each operation.
The following example shows how to connect to a sharded cluster and specify a secondary read preference in your connection string:
val shardedClient = MongoClient.create( "mongodb://user:password@mongos1.example.com,mongos2.example.com/?readPreference=secondary" )
Tag Sets
In MongoDB server, you can apply key-value tags to replica set members according to any criteria you choose. You can then use those tags to target one or more members for a read operation.
By default, the Kotlin driver ignores tags when choosing a member to read from. To instruct the Kotlin driver to prefer certain tags, pass the tags as a list to your read preference setter method.
Suppose you are connected to a replica set that contains members hosted at multiple data centers across the United States. You want the driver to prefer reads from secondary replica set members in the following order:
Members from the New York data center, tagged with
("dc", "ny")Members from the San Francisco data center, tagged with
("dc", "sf")Any secondary members
This code example passes a list of tags representing the preceding replica set members to the ReadPreference.secondary() setter method. Then, the code passes the read preference information to the withReadPreference() method to set the read order on the database:
val tag1 = TagSet(Tag("dc", "ny")) val tag2 = TagSet(Tag("dc", "sf")) val tag3 = TagSet() // Empty tag set as fallback val readPref = ReadPreference.secondary(listOf(tag1, tag2, tag3)) val taggedDb = mongoClient.getDatabase("test_database") .withReadPreference(readPref)
Load Balancing
When connecting to a sharded cluster or a replica set, the Kotlin driver uses load balancing to handle read and write requests. Load balancing allows the driver to distribute these requests across multiple servers, which avoids overwhelming any one server and ensures optimal performance.
When connecting to a sharded cluster, the Kotlin driver determines the closest mongos instance by calculating which one has the lowest network round-trip time. Then, the driver determines the latency window by adding this mongos's average round-trip time to the localThresholdMS value. The driver load balances requests across up to two random mongos instances that fall within the latency window. For each request, the driver chooses the server with the lower operation load by determining its operationCount value.
When connecting to a replica set, the Kotlin driver first selects replica set members according to your read preference. Then, the driver follows the same process as described in the preceding paragraph. After calculating the latency window, the driver selects up to two random replica set members that fall within the window and chooses the member with the lower operationCount value to receive the request.
Tip
To learn more about load balancing, see Sharded Cluster Balancer in the MongoDB server manual.
Local Threshold
The Kotlin driver uses the local threshold value to calculate the latency window for server selection. This value determines the servers that are eligible to receive read and write requests.
When connecting to a replica set with a non-primary read preference, the driver reads from the nearest eligible replica set member within the latency window. When connecting to a sharded cluster, the driver selects from all reachable mongos instances within the latency window. To learn about read preference modes, see Read
Preference.
By default, the driver uses only those servers whose ping times are within 15 milliseconds of the nearest eligible server.
For example, suppose your replica set has five members and the nearest member has a ping time of 5 milliseconds. With the default localThresholdMS of 15 milliseconds, only members with a ping time of 20 milliseconds or less are within the latency window, as shown in the following table:
Host | Type | Ping Time | Within Latency Window |
|---|---|---|---|
| Primary | 5ms | Yes |
| Secondary | 9ms | Yes |
| Secondary | 13ms | Yes |
| Secondary | 24ms | No |
| Secondary | 42ms | No |
To adjust the latency window, set the localThreshold option in a MongoClientSettings instance or the localThresholdMS option in your connection URI.
Note
When selecting replica set members from a single mongos instance, the Kotlin driver ignores the localThresholdMS option. In this case, use the localThreshold command-line option.
The following example connects to a replica set and specifies a local threshold of 35 milliseconds. Select the MongoClientSettings or Connection URI tab to see corresponding code for each approach:
val latencySettings = MongoClientSettings.builder() .applyConnectionString(ConnectionString("mongodb://localhost:27017/")) .applyToClusterSettings { builder -> builder.localThreshold(35, TimeUnit.MILLISECONDS) } .build() val latencyClient2 = MongoClient.create(latencySettings)
val latencyClient1 = MongoClient.create( "mongodb://localhost:27017/?replicaSet=repl0&localThresholdMS=35" )
In the preceding example, the Kotlin driver distributes reads among matching members within 35 milliseconds of the closest member's ping time.
Retryable Reads and Writes
The Kotlin driver automatically retries certain read and write operations a single time if they fail due to a network or server error.
You can explicitly disable retryable reads or retryable writes by setting the retryReads or retryWrites option to false in a MongoClientSettings instance. You can also set the retryReads or retryWrites options in your connection URI.
The following example sets both retryable reads and retryable writes to false. Select the MongoClientSettings or Connection URI tab to see corresponding code for each approach:
val retrySettings = MongoClientSettings.builder() .applyConnectionString(ConnectionString("mongodb://localhost:27017/")) .retryReads(false) // Disables automatic retries of read operations .retryWrites(false) // Disables automatic retries of write operations .build() val retryClient = MongoClient.create(retrySettings)
val retryUri = "mongodb://localhost:27017/?retryReads=false&retryWrites=false" val retryUriClient = MongoClient.create(retryUri)
To learn more about supported retryable read operations, see Retryable Reads in the MongoDB server manual. To learn more about supported retryable write operations, see Retryable Writes in the MongoDB server manual.
API Documentation
To learn more about any of the methods or types discussed in this guide, see the following API documentation: