Connecting to the replica set in the shell to query and insert data
In the previous recipe, we started a replica set of three mongod processes. In this recipe, we will work with this setup by connecting to it using the mongo client application, perform queries, insert data, and take a look at some of the interesting aspects of a replica set from a client's perspective.
Getting ready
The prerequisite for this recipe is that the replica set should be set up and running. Refer to the previous recipe, Starting multiple instances as part of a replica set, for details on how to start the replica set.
How to do it…
- We will start two shells here, one for
PRIMARY
and one forSECONDARY
. Execute the following command on the command prompt:> mongo localhost:27000
- The prompt of the shell tells us whether the server to which we have connected is
PRIMARY
orSECONDARY
. It should show the replica set's name followed by a:
, followed by the server state. In this case, if the replica set is initialized, up, and running, we should see eitherrepSetTest:PRIMARY>
orrepSetTest:SECONDARY>
. - Suppose that the first server we connected to is a secondary, we need to find the primary. Execute the
rs.status()
command in the shell and look out for thestateStr
field. This should give us the primary server. Use the mongo shell to connect to this server. - At this point, we should be having two shells running, one connected to a primary and another connected to a secondary.
- In the shell connected to the primary node, execute the following insert:
repSetTest:PRIMARY> db.replTest.insert({_id:1, value:'abc'})
- There is nothing special about this. We just inserted a small document in a collection that we will use for the replication test.
- By executing the following query on the primary, we should get the following result:
repSetTest:PRIMARY> db.replTest.findOne() { "_id" : 1, "value" : "abc" }
- So far, so good. Now, we will go to the shell that is connected to the
SECONDARY
node and execute the following:repSetTest:SECONDARY> db.replTest.findOne()
On doing this, we should see the following error on the console:
{ "$err" : "not master and slaveOk=false", "code" : 13435 }
- Now execute the following on the console:
repSetTest:SECONDARY> rs.slaveOk(true)
- Execute the query that we executed in step 7 again on the shell. This should now get the results as follows:
repSetTest:SECONDARY>db.replTest.findOne() { "_id" : 1, "value" : "abc" }
- Execute the following insert on the secondary node; it should not succeed with the following message:
repSetTest:SECONDARY> db.replTest.insert({_id:1, value:'abc'}) not master
How it works…
We have done a lot of things in this recipe, and we will try to throw some light on some of the important concepts to remember.
We basically connect to a primary and secondary node from the shell and perform (I would say, try to perform) selects and inserts. The architecture of a Mongo replica set is made of one primary (just one, no more, no less) and multiple secondary nodes. All writes happen on the PRIMARY
only. Note that replication is not a mechanism to distribute the read request load that enables scaling the system. Its primary intent is to ensure high availability of data. By default, we are not permitted to read data from the secondary nodes. In step 6, we simply insert data from the primary node and then execute a query to get the document that we inserted. This is straightforward and nothing related to clustering here. Just note that we inserted the document from the primary and then queried it back.
In the next step, we execute the same query but this time, from the secondary's shell. By default, querying is not enabled on the SECONDARY
. There might be a small lag in replicating the data possibly due to heavy data volumes to be replicated, network latency, or hardware capacity to name a few of the causes, and thus, querying on the secondary might not reflect the latest inserts or updates made on the primary. However, if we are ok with it and can live with the slight lag in the data being replicated, all we need to do is enable querying on the SECONDARY
node explicitly by just executing one command, rs.slaveOk()
or rs.slaveOk(true)
. Once this is done, we are free to execute queries on the secondary nodes too.
Finally, we try to insert the data into a collection of the slave node. Under no circumstances is this permitted, regardless of whether we have done rs.slaveOk()
. When rs.slaveOk()
is invoked, it just permits the data to be queried from the SECONDARY
node. All write operations still have to go to the primary and then flow down to the secondary. The internals of replication will be covered in a different recipe in the administration section.
See also
The next recipe, Connecting to the replica set to query and insert data from a Java client, is about connecting to a replica set from a Java client.