11

I have a mongodb replica set from which I want to read data from primary and secondary db.

I have used this command to connect to the db:

mongoose.connect('mongodb://user:password@54.230.1.1,user:password@54.230.1.2,user:password@54.230.1.3/PanPanDB?replicaSet=rs0&readPreference=nearest');

It doesn't work.. My application continues to read from the primary.. Any suggestion please?

Michele Spina
  • 1,091
  • 4
  • 12
  • 21

6 Answers6

12

If you want to read from a secondary, you should set your read preference to either of:

  • secondaryPreferred - In most situations, operations read from secondary members but if no secondary members are available, operations read from the primary.

  • secondary - All operations read from the secondary members of the replica set.

Reading from nearest as per your example will select the nearest member by ping time (which could be either the primary or a secondary).

Caveats

When using any read preference other than primary, you need to be aware of potential issues with eventual consistency that may affect your application logic. For example, if you are reading from a secondary there may be changes on the primary that have not replicated to that secondary yet.

If you are concerned about stronger consistency when reading from secondaries you should review the Write Concern for Replica Sets documentation.

Since secondaries have to write the same data as the primary, reading from secondaries may not improve performance unless your application is very read heavy or is fine with eventual consistency.

Stennie
  • 63,885
  • 14
  • 149
  • 175
  • 2
    This answer could be improved with some Mongoose-specific syntax, since the question included the "mongoose" tag. – Mark Stosberg Jan 21 '14 at 17:27
  • 1
    @MarkStosberg Belated reply to an old comment as I seemed to have missed the original notification. FYI, the Mongoose connection example is already in the question text, it was just an incorrect expectation on how the readPreference of "nearest" works. Mongoose supports the standard [MongoDB Connection String format](http://docs.mongodb.org/manual/reference/connection-string/) or an [options object](http://mongoosejs.com/docs/connections.html) with equivalent values. Arguably this question shouldn't be tagged Mongoose since it's really about the general read preference behaviour. – Stennie Jan 28 '15 at 11:46
  • Why that isn't the default for reads is completely beyond me. – Tom O'Connor Mar 10 '20 at 16:25
  • @TomO'Connor The default is to have strongly consistent reads from the primary. Reading from secondaries is eventually consistent which doesn't work for all use cases. – Stennie Mar 10 '20 at 21:30
8

Following the documentation found on MongoDB website and on Mongoose web site, you can add this instruction for configuring the ReadPreference on Mongoose:

var opts = { replSet: {readPreference: 'ReadPreference.NEAREST'} };

mongoose.connect('mongodb://###:###@###:###/###', opts);

This has been tested using Mongoose version 3.8.9

emas
  • 668
  • 8
  • 17
  • 7
    According to the mongoose documentation you need to use `replset`, with a small `s`. MongoDB uses the capital `S`. This difference caused me some trouble... – Michiel Oct 22 '15 at 08:18
  • 4
    You should use 'nearest' as a string. ReadPreference.NEAREST is just a definition. You should check the source code: https://github.com/mongodb/node-mongodb-native/blob/5d2b36ca5f1b3f7ccf51750387568367df0a40c1/lib/read_preference.js#L126 – Gergo Mar 21 '17 at 15:18
8

As well as setting the connection URI (as you did) and the connection options (as Emas did), I also had to explicitly choose the server for each query, e.g.

var query = User.find({}).read("nearest");
query.exec(function(err, users) {
    // ...
});
chichilatte
  • 1,697
  • 19
  • 21
  • Thanks for this, is .read("nearest") documented anywhere? where did you find this? – JasonY Apr 05 '18 at 14:39
  • 2
    God it was a while ago. I would have found it on github or stackoverflow probably. It's documented in the mongoose API docs... http://mongoosejs.com/docs/api.html#query_Query-read – chichilatte Apr 05 '18 at 15:15
3

Mongoose use node package "mongodb", connection uri or opts is parsed by "mongodb". Here is mongodb connect opts and mongodb readPreference source code.

So, we can use mongoose like this:

var opts = {db: {readPreference: 'nearest'}; mongoose.connect(uri, opts);

Also, just use uri like this:

var uri = 'mongodb://###?readPreference=nearest'; mongoose.connect(uri, opts);

In mongoose 4.3.4 above take effect.

efei
  • 281
  • 1
  • 3
  • 14
3

This is the proper instantiation in Mongoose v5.9.5:

const opts = {
    readPreference: 'nearest',
}
mongoose.connect(MONGODB_CONNECTION, opts)

These are the different string values depending on the preference type you're looking for:

ReadPreference.PRIMARY = 'primary';
ReadPreference.PRIMARY_PREFERRED = 'primaryPreferred';
ReadPreference.SECONDARY = 'secondary';
ReadPreference.SECONDARY_PREFERRED = 'secondaryPreferred';
ReadPreference.NEAREST = 'nearest'
McLovin
  • 1,455
  • 3
  • 19
  • 37
  • Setting the readPreference as option throws an error for me, a weird one too.. `TypeError: Reduce of empty array with no initial value` – O'Dane Brissett Aug 10 '20 at 22:18
2

You can simply do that by using below code

var collection = db.collection(collectionName,{readPreference:'secondaryPreferred'});

http://p1bugs.blogspot.in/2016/06/scaling-read-query-load-on-mongodb.html

mikdiet
  • 9,859
  • 8
  • 59
  • 68