diff --git a/README.md b/README.md index 0d3e63f..51a35e8 100644 --- a/README.md +++ b/README.md @@ -84,14 +84,17 @@ require('mongodb').connect(uri, function (err, db) { - [where](#where) - [$where](#where-1) - [batchSize](#batchsize) +- [collation](#collation) - [comment](#comment) - [hint](#hint) - [limit](#limit) - [maxScan](#maxscan) - [maxTime](#maxtime) +- [maxTimeMS](#maxtime) - [skip](#skip) - [sort](#sort) - [read](#read) +- [readConcern](#readconcern) - [slaveOk](#slaveok) - [snapshot](#snapshot) - [tailable](#tailable) @@ -821,6 +824,16 @@ _Cannot be used with `distinct()`._ [MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.batchSize/) +### collation() + +Specifies the collation option. + +```js +query.collation({ locale: "en_US", strength: 1 }) +``` + +[MongoDB documentation](https://docs.mongodb.com/manual/reference/method/cursor.collation/#cursor.collation) + ### comment() Specifies the comment option. @@ -875,6 +888,7 @@ Specifies the maxTimeMS option. ```js query.maxTime(100) +query.maxTimeMS(100) ``` [MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.maxTimeMS/) @@ -964,6 +978,46 @@ mquery(..).read(preference).exec(); Read more about how to use read preferences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences). + +### readConcern() + +Sets the readConcern option for the query. + +```js +mquery().readConcern('local') +mquery().readConcern('l') // same as local + +mquery().readConcern('available') +mquery().readConcern('a') // same as available + +mquery().readConcern('majority') +mquery().readConcern('m') // same as majority + +mquery().readConcern('linearizable') +mquery().readConcern('lz') // same as linearizable + +mquery().readConcern('snapshot') +mquery().readConcern('s') // same as snapshot +``` + +##### Read Concern Level: + +- `local` - The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back). (MongoDB 3.2+) +- `available` - The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back). (MongoDB 3.6+) +- `majority` - The query returns the data that has been acknowledged by a majority of the replica set members. The documents returned by the read operation are durable, even in the event of failure. (MongoDB 3.2+) +- `linearizable` - Read from a secondary if available, otherwise read from the primary. (MongoDB 3.4+) +- `snapshot` - The query returns data that reflects all successful majority-acknowledged writes that completed prior to the start of the read operation. The query may wait for concurrently executing writes to propagate to a majority of replica set members before returning results. (MongoDB 4.0+) + +Aliases + +- `l` local +- `a` available +- `m` majority +- `lz` linearizable +- `s` snapshot + +Read more about how to use read concern [here](https://docs.mongodb.com/manual/reference/read-concern/). + ### slaveOk() Sets the slaveOk option. `true` allows reading from secondaries. diff --git a/lib/mquery.js b/lib/mquery.js index 1515f01..cb776a8 100644 --- a/lib/mquery.js +++ b/lib/mquery.js @@ -204,6 +204,24 @@ Query.prototype.collection = function collection (coll) { return this; } +/** + * Adds a collation to this op (MongoDB 3.4 and up) + * + * ####Example + * + * query.find().collation({ locale: "en_US", strength: 1 }) + * + * @param {Object} value + * @return {Query} this + * @see MongoDB docs https://docs.mongodb.com/manual/reference/method/cursor.collation/#cursor.collation + * @api public + */ + +Query.prototype.collation = function(value) { + this.options.collation = value; + return this; +}; + /** * Specifies a `$where` condition * @@ -1447,6 +1465,7 @@ function _pushMap (opts, map) { * ####Example * * query.maxTime(100) + * query.maxTimeMS(100) * * @method maxTime * @memberOf Query @@ -1455,7 +1474,7 @@ function _pushMap (opts, map) { * @api public */ -Query.prototype.maxTime = function (v) { +Query.prototype.maxTime = Query.prototype.maxTimeMS = function (v) { this._validate('maxTime'); this.options.maxTimeMS = v; return this; @@ -1610,6 +1629,57 @@ Query.prototype.read = function (pref) { return this; } +/** + * Sets the readConcern option for the query. + * + * ####Example: + * + * new Query().readConcern('local') + * new Query().readConcern('l') // same as local + * + * new Query().readConcern('available') + * new Query().readConcern('a') // same as available + * + * new Query().readConcern('majority') + * new Query().readConcern('m') // same as majority + * + * new Query().readConcern('linearizable') + * new Query().readConcern('lz') // same as linearizable + * + * new Query().readConcern('snapshot') + * new Query().readConcern('s') // same as snapshot + * + * + * ####Read Concern Level: + * + * local MongoDB 3.2+ The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back). + * available MongoDB 3.6+ The query returns from the instance with no guarantee guarantee that the data has been written to a majority of the replica set members (i.e. may be rolled back). + * majority MongoDB 3.2+ The query returns the data that has been acknowledged by a majority of the replica set members. The documents returned by the read operation are durable, even in the event of failure. + * linearizable MongoDB 3.4+ Read from a secondary if available, otherwise read from the primary. + * snapshot MongoDB 4.0+ The query returns data that reflects all successful majority-acknowledged writes that completed prior to the start of the read operation. The query may wait for concurrently executing writes to propagate to a majority of replica set members before returning results. + * + * + * Aliases + * + * l local + * a available + * m majority + * lz linearizable + * s snapshot + * + * Read more about how to use read concern [here](https://docs.mongodb.com/manual/reference/read-concern/). + * + * @param {String} level one of the listed read concern level or their aliases + * @see mongodb https://docs.mongodb.com/manual/reference/read-concern/ + * @return {Query} this + * @api public + */ + +Query.prototype.readConcern = function (level) { + this.options.readConcern = utils.readConcern(level) + return this +} + /** * Sets tailable option. * diff --git a/lib/utils.js b/lib/utils.js index 69b7d8a..64d01c3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -211,6 +211,45 @@ exports.readPref = function readPref (pref) { return pref; } + +/** + * Read Concern helper (mongo 3.2 drivers support this) + * + * Allows using string to specify read concern level: + * + * local 3.2+ + * available 3.6+ + * majority 3.2+ + * linearizable 3.4+ + * snapshot 4.0+ + * + * @param {String} readConcern + */ + +exports.readConcern = function readConcern (concern) { + if ('string' === typeof concern) { + switch (concern) { + case 'l': + concern = 'local' + break; + case 'a': + concern = 'available'; + break; + case 'm': + concern = 'majority'; + break; + case 'lz': + concern = 'linearizable'; + break; + case 's': + concern = 'snapshot'; + break; + } + concern = { level: concern } + } + return concern +} + /** * Object.prototype.toString.call helper */ @@ -303,7 +342,7 @@ var soon = exports.soon = 'function' == typeof setImmediate */ exports.cloneBuffer = function (buff) { - var dupe = new Buffer(buff.length); + var dupe = Buffer.alloc(buff.length); buff.copy(dupe, 0, 0, buff.length); return dupe; }; diff --git a/test/index.js b/test/index.js index b041377..ea1f37e 100644 --- a/test/index.js +++ b/test/index.js @@ -1304,6 +1304,18 @@ describe('mquery', function(){ }) }) + describe('readConcern', function(){ + it('sets associated readConcern option', function(){ + var m = mquery(); + m.readConcern('s'); + assert.deepEqual({ level: 'snapshot' }, m.options.readConcern); + }) + it('is chainable', function(){ + var m = mquery(); + assert.equal(m, m.readConcern('lz')); + }) + }) + describe('tailable', function(){ it('works', function(){ var query = mquery(); @@ -2522,6 +2534,40 @@ describe('mquery', function(){ done(); }) }) + + it('works with readConcern', function (done) { + var m = mquery(col).find({ name: 'exec' }); + try { + m.readConcern('l'); + } catch (e) { + if (e.code === 'MODULE_NOT_FOUND') + e = null; + done(e); + return; + } + m.exec(function (err, docs) { + assert.ifError(err); + assert.equal(2, docs.length); + done(); + }) + }) + + it('works with collation', function (done) { + var m = mquery(col).find({ name: 'EXEC' }); + try { + m.collation({ locale: "en_US", strength: 1 }) + } catch (e) { + if (e.code === 'MODULE_NOT_FOUND') + e = null; + done(e); + return; + } + m.exec(function (err, docs) { + assert.ifError(err); + assert.equal(2, docs.length); + done(); + }) + }) }); it('findOne', function(done){ diff --git a/test/utils.test.js b/test/utils.test.js index fa5972a..84d0bd0 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -103,7 +103,7 @@ describe('lib/utils', function() { it('clones mongodb.Binary', function(done){ if (!mongo) return done(); - var buf = new Buffer('hi'); + var buf = Buffer.from('hi'); var binary= new mongo.Binary(buf, 2); var clone = utils.clone(binary); assert.equal(binary.sub_type, clone.sub_type); @@ -129,7 +129,7 @@ describe('lib/utils', function() { }); it('handles buffers', function(done){ - var buff = new Buffer(10); + var buff = Buffer.alloc(10); buff.fill(1); var clone = utils.clone(buff);