mongodb 2.2.26 → 2.2.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/HISTORY.md CHANGED
@@ -1,3 +1,50 @@
1
+ 2.2.30 2017-07-07
2
+ -----------------
3
+ * Update mongodb-core to 2.2.14
4
+ * MongoClient
5
+ * add `appname` to list of valid option names
6
+ * added test for passing appname as option
7
+ * NODE-1052 ensure user options are applied while parsing connection string uris
8
+
9
+ 2.2.29 2017-06-19
10
+ -----------------
11
+ * Update mongodb-core to 2.1.13
12
+ * NODE-1039 ensure we force destroy server instances, forcing queue to be flushed.
13
+ * Use actual server type in standalone SDAM events.
14
+ * Allow multiple map calls (Issue #1521, https://github.com/Robbilie).
15
+ * Clone insertMany options before mutating (Issue #1522, https://github.com/vkarpov15).
16
+ * NODE-1034 Fix GridStore issue caused by Node 8.0.0 breaking backward compatible fs.read API.
17
+ * NODE-1026, use operator instead of skip function in order to avoid useless fetch stage.
18
+
19
+ 2.2.28 2017-06-02
20
+ -----------------
21
+ * Update mongodb-core to 2.1.12
22
+ * NODE-1019 Set keepAlive to 300 seconds or 1/2 of socketTimeout if socketTimeout < keepAlive.
23
+ * Minor fix to report the correct state on error.
24
+ * NODE-1020 'family' was added to options to provide high priority for ipv6 addresses (Issue #1518, https://github.com/firej).
25
+ * Fix require_optional loading of bson-ext.
26
+ * Ensure no errors are thrown by replset if topology is destroyed before it finished connecting.
27
+ * NODE-999 SDAM fixes for Mongos and single Server event emitting.
28
+ * NODE-1014 Set socketTimeout to default to 360 seconds.
29
+ * NODE-1019 Set keepAlive to 300 seconds or 1/2 of socketTimeout if socketTimeout < keepAlive.
30
+ * Just handle Collection name errors distinctly from general callback errors avoiding double callbacks in Db.collection.
31
+ * NODE-999 SDAM fixes for Mongos and single Server event emitting.
32
+ * NODE-1000 Added guard condition for upload.js checkDone function in case of race condition caused by late arriving chunk write.
33
+
34
+ 2.2.27 2017-05-22
35
+ -----------------
36
+ * Updated mongodb-core to 2.1.11
37
+ * NODE-987 Clear out old intervalIds on when calling topologyMonitor.
38
+ * NODE-987 Moved filtering to pingServer method and added test case.
39
+ * Check for connection destroyed just before writing out and flush out operations correctly if it is (Issue #179, https://github.com/jmholzinger).
40
+ * NODE-989 Refactored Replicaset monitoring to correcly monitor newly added servers, Also extracted setTimeout and setInterval to use custom wrappers Timeout and Interval.
41
+ * NODE-985 Deprecated Db.authenticate and Admin.authenticate and moved auth methods into authenticate.js to ensure MongoClient.connect does not print deprecation warnings.
42
+ * NODE-988 Merged readConcern and hint correctly on collection(...).find(...).count()
43
+ * Fix passing the readConcern option to MongoClient.connect (Issue #1514, https://github.com/bausmeier).
44
+ * NODE-996 Propegate all events up to a MongoClient instance.
45
+ * Allow saving doc with null `_id` (Issue #1517, https://github.com/vkarpov15).
46
+ * NODE-993 Expose hasNext for command cursor and add docs for both CommandCursor and Aggregation Cursor.
47
+
1
48
  2.2.26 2017-04-18
2
49
  -----------------
3
50
  * Updated mongodb-core to 2.1.10
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/mongodb/node-mongodb-native.svg?branch=2.1)](http://travis-ci.org/mongodb/node-mongodb-native)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/mongodb/node-mongodb-native/badge.svg?branch=2.1)](https://coveralls.io/github/mongodb/node-mongodb-native?branch=2.1)
5
- [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/mongodb/node-mongodb-native?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
5
+ [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mongodb/node-mongodb-native?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
6
6
 
7
7
  # Description
8
8
 
package/lib/admin.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  var toError = require('./utils').toError,
4
4
  Define = require('./metadata'),
5
- shallowClone = require('./utils').shallowClone;
5
+ shallowClone = require('./utils').shallowClone,
6
+ assign = require('./utils').assign,
7
+ authenticate = require('./authenticate');
6
8
 
7
9
  /**
8
10
  * @fileOverview The **Admin** class is an internal class that allows convenient access to
@@ -239,23 +241,23 @@ define.classMethod('ping', {callback: true, promise:true});
239
241
  * @param {string} [password] The password.
240
242
  * @param {Admin~resultCallback} [callback] The command result callback
241
243
  * @return {Promise} returns Promise if no callback passed
244
+ * @deprecated This method will no longer be available in the next major release 3.x as MongoDB 3.6 will only allow auth against users in the admin db and will no longer allow multiple credentials on a socket. Please authenticate using MongoClient.connect with auth credentials.
242
245
  */
243
246
  Admin.prototype.authenticate = function(username, password, options, callback) {
244
- var self = this;
245
- if(typeof options == 'function') callback = options, options = {};
246
- options = shallowClone(options);
247
- options.authdb = 'admin';
248
-
249
- // Execute using callback
250
- if(typeof callback == 'function') return this.s.db.authenticate(username, password, options, callback);
247
+ console.warn("Admin.prototype.authenticate method will no longer be available in the next major release 3.x as MongoDB 3.6 will only allow auth against users in the admin db and will no longer allow multiple credentials on a socket. Please authenticate using MongoClient.connect with auth credentials.");
248
+ var finalArguments = [this.s.db];
249
+ if(typeof username == 'string') finalArguments.push(username);
250
+ if(typeof password == 'string') finalArguments.push(password);
251
+ if(typeof options == 'function') {
252
+ finalArguments.push({ authdb: 'admin' });
253
+ finalArguments.push(options);
254
+ } else {
255
+ finalArguments.push(assign({}, options, { authdb: 'admin' }));
256
+ }
251
257
 
252
- // Return a Promise
253
- return new this.s.promiseLibrary(function(resolve, reject) {
254
- self.s.db.authenticate(username, password, options, function(err, r) {
255
- if(err) return reject(err);
256
- resolve(r);
257
- });
258
- });
258
+ if(typeof callback == 'function') finalArguments.push(callback);
259
+ // Excute authenticate method
260
+ return authenticate.apply(this.s.db, finalArguments);
259
261
  }
260
262
 
261
263
  define.classMethod('authenticate', {callback: true, promise:true});
@@ -316,6 +316,7 @@ AggregationCursor.prototype.get = AggregationCursor.prototype.toArray;
316
316
  define.classMethod('toArray', {callback: true, promise:true});
317
317
  define.classMethod('each', {callback: true, promise:false});
318
318
  define.classMethod('forEach', {callback: true, promise:false});
319
+ define.classMethod('hasNext', {callback: true, promise:true});
319
320
  define.classMethod('next', {callback: true, promise:true});
320
321
  define.classMethod('close', {callback: true, promise:true});
321
322
  define.classMethod('isClosed', {callback: false, promise:false, returns: [Boolean]});
@@ -331,6 +332,14 @@ define.classMethod('readBufferedDocuments', {callback: false, promise:false, ret
331
332
  * @return {Promise} returns Promise if no callback passed
332
333
  */
333
334
 
335
+ /**
336
+ * Check if there is any document still available in the cursor
337
+ * @function AggregationCursor.prototype.hasNext
338
+ * @param {AggregationCursor~resultCallback} [callback] The result callback.
339
+ * @throws {MongoError}
340
+ * @return {Promise} returns Promise if no callback passed
341
+ */
342
+
334
343
  /**
335
344
  * The callback format for results
336
345
  * @callback AggregationCursor~toArrayResultCallback
@@ -0,0 +1,109 @@
1
+ var shallowClone = require('./utils').shallowClone
2
+ , handleCallback = require('./utils').handleCallback
3
+ , MongoError = require('mongodb-core').MongoError;
4
+
5
+ var authenticate = function(self, username, password, options, callback) {
6
+ // Did the user destroy the topology
7
+ if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
8
+
9
+ // the default db to authenticate against is 'self'
10
+ // if authententicate is called from a retry context, it may be another one, like admin
11
+ var authdb = options.dbName ? options.dbName : self.databaseName;
12
+ authdb = self.authSource ? self.authSource : authdb;
13
+ authdb = options.authdb ? options.authdb : authdb;
14
+ authdb = options.authSource ? options.authSource : authdb;
15
+
16
+ // Callback
17
+ var _callback = function(err, result) {
18
+ if(self.listeners('authenticated').length > 0) {
19
+ self.emit('authenticated', err, result);
20
+ }
21
+
22
+ // Return to caller
23
+ handleCallback(callback, err, result);
24
+ }
25
+
26
+ // authMechanism
27
+ var authMechanism = options.authMechanism || '';
28
+ authMechanism = authMechanism.toUpperCase();
29
+
30
+ // If classic auth delegate to auth command
31
+ if(authMechanism == 'MONGODB-CR') {
32
+ self.s.topology.auth('mongocr', authdb, username, password, function(err) {
33
+ if(err) return handleCallback(callback, err, false);
34
+ _callback(null, true);
35
+ });
36
+ } else if(authMechanism == 'PLAIN') {
37
+ self.s.topology.auth('plain', authdb, username, password, function(err) {
38
+ if(err) return handleCallback(callback, err, false);
39
+ _callback(null, true);
40
+ });
41
+ } else if(authMechanism == 'MONGODB-X509') {
42
+ self.s.topology.auth('x509', authdb, username, password, function(err) {
43
+ if(err) return handleCallback(callback, err, false);
44
+ _callback(null, true);
45
+ });
46
+ } else if(authMechanism == 'SCRAM-SHA-1') {
47
+ self.s.topology.auth('scram-sha-1', authdb, username, password, function(err) {
48
+ if(err) return handleCallback(callback, err, false);
49
+ _callback(null, true);
50
+ });
51
+ } else if(authMechanism == 'GSSAPI') {
52
+ if(process.platform == 'win32') {
53
+ self.s.topology.auth('sspi', authdb, username, password, options, function(err) {
54
+ if(err) return handleCallback(callback, err, false);
55
+ _callback(null, true);
56
+ });
57
+ } else {
58
+ self.s.topology.auth('gssapi', authdb, username, password, options, function(err) {
59
+ if(err) return handleCallback(callback, err, false);
60
+ _callback(null, true);
61
+ });
62
+ }
63
+ } else if(authMechanism == 'DEFAULT') {
64
+ self.s.topology.auth('default', authdb, username, password, function(err) {
65
+ if(err) return handleCallback(callback, err, false);
66
+ _callback(null, true);
67
+ });
68
+ } else {
69
+ handleCallback(callback, MongoError.create({message: f("authentication mechanism %s not supported", options.authMechanism), driver:true}));
70
+ }
71
+ }
72
+
73
+ module.exports = function(self, username, password, options, callback) {
74
+ if(typeof options == 'function') callback = options, options = {};
75
+ // Shallow copy the options
76
+ options = shallowClone(options);
77
+
78
+ // Set default mechanism
79
+ if(!options.authMechanism) {
80
+ options.authMechanism = 'DEFAULT';
81
+ } else if(options.authMechanism != 'GSSAPI'
82
+ && options.authMechanism != 'DEFAULT'
83
+ && options.authMechanism != 'MONGODB-CR'
84
+ && options.authMechanism != 'MONGODB-X509'
85
+ && options.authMechanism != 'SCRAM-SHA-1'
86
+ && options.authMechanism != 'PLAIN') {
87
+ return handleCallback(callback, MongoError.create({message: "only DEFAULT, GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR is supported by authMechanism", driver:true}));
88
+ }
89
+
90
+ // If we have a callback fallback
91
+ if(typeof callback == 'function') return authenticate(self, username, password, options, function(err, r) {
92
+ // Support failed auth method
93
+ if(err && err.message && err.message.indexOf('saslStart') != -1) err.code = 59;
94
+ // Reject error
95
+ if(err) return callback(err, r);
96
+ callback(null, r);
97
+ });
98
+
99
+ // Return a promise
100
+ return new self.s.promiseLibrary(function(resolve, reject) {
101
+ authenticate(self, username, password, options, function(err, r) {
102
+ // Support failed auth method
103
+ if(err && err.message && err.message.indexOf('saslStart') != -1) err.code = 59;
104
+ // Reject error
105
+ if(err) return reject(err);
106
+ resolve(r);
107
+ });
108
+ });
109
+ };
package/lib/collection.js CHANGED
@@ -496,7 +496,7 @@ define.classMethod('insertOne', {callback: true, promise:true});
496
496
  Collection.prototype.insertMany = function(docs, options, callback) {
497
497
  var self = this;
498
498
  if(typeof options == 'function') callback = options, options = {};
499
- options = options || {ordered:true};
499
+ options = options ? shallowClone(options) : {ordered:true};
500
500
  if(!Array.isArray(docs) && typeof callback == 'function') {
501
501
  return callback(MongoError.create({message: 'docs parameter must be an array of documents', driver:true }));
502
502
  } else if(!Array.isArray(docs)) {
@@ -736,7 +736,7 @@ var insertDocuments = function(self, docs, options, callback) {
736
736
  // Add _id if not specified
737
737
  if(forceServerObjectId !== true){
738
738
  for(var i = 0; i < docs.length; i++) {
739
- if(docs[i]._id == null) docs[i]._id = self.s.pkFactory.createPk();
739
+ if(docs[i]._id === void 0) docs[i]._id = self.s.pkFactory.createPk();
740
740
  }
741
741
  }
742
742
 
@@ -2040,7 +2040,7 @@ var count = function(self, query, options, callback) {
2040
2040
  if(typeof skip == 'number') cmd.skip = skip;
2041
2041
  if(typeof limit == 'number') cmd.limit = limit;
2042
2042
  if(typeof maxTimeMS == 'number') cmd.maxTimeMS = maxTimeMS;
2043
- if(hint) options.hint = hint;
2043
+ if(hint) cmd.hint = hint;
2044
2044
 
2045
2045
  options = shallowClone(options);
2046
2046
  // Ensure we have the right read preference inheritance
@@ -131,7 +131,7 @@ var CommandCursor = function(bson, ns, cmd, options, topology, topologyOptions)
131
131
  inherits(CommandCursor, Readable);
132
132
 
133
133
  // Set the methods to inherit from prototype
134
- var methodsToInherit = ['_next', 'next', 'each', 'forEach', 'toArray'
134
+ var methodsToInherit = ['_next', 'next', 'hasNext', 'each', 'forEach', 'toArray'
135
135
  , 'rewind', 'bufferedCount', 'readBufferedDocuments', 'close', 'isClosed', 'kill', 'setCursorBatchSize'
136
136
  , '_find', '_getmore', '_killcursor', 'isDead', 'explain', 'isNotified', 'isKilled'];
137
137
 
@@ -207,6 +207,7 @@ define.classMethod('toArray', {callback: true, promise:true});
207
207
  define.classMethod('each', {callback: true, promise:false});
208
208
  define.classMethod('forEach', {callback: true, promise:false});
209
209
  define.classMethod('next', {callback: true, promise:true});
210
+ define.classMethod('hasNext', {callback: true, promise:true});
210
211
  define.classMethod('close', {callback: true, promise:true});
211
212
  define.classMethod('isClosed', {callback: false, promise:false, returns: [Boolean]});
212
213
  define.classMethod('rewind', {callback: false, promise:false});
@@ -221,6 +222,14 @@ define.classMethod('readBufferedDocuments', {callback: false, promise:false, ret
221
222
  * @return {Promise} returns Promise if no callback passed
222
223
  */
223
224
 
225
+ /**
226
+ * Check if there is any document still available in the cursor
227
+ * @function CommandCursor.prototype.hasNext
228
+ * @param {CommandCursor~resultCallback} [callback] The result callback.
229
+ * @throws {MongoError}
230
+ * @return {Promise} returns Promise if no callback passed
231
+ */
232
+
224
233
  /**
225
234
  * The callback format for results
226
235
  * @callback CommandCursor~toArrayResultCallback
package/lib/cursor.js CHANGED
@@ -941,6 +941,16 @@ var count = function(self, applySkipLimit, opts, callback) {
941
941
  'count': self.s.ns.substr(delimiter+1), 'query': self.s.cmd.query
942
942
  }
943
943
 
944
+ // Apply a readConcern if set
945
+ if(self.s.cmd.readConcern) {
946
+ command.readConcern = self.s.cmd.readConcern;
947
+ }
948
+
949
+ // Apply a hint if set
950
+ if(self.s.cmd.hint) {
951
+ command.hint = self.s.cmd.hint;
952
+ }
953
+
944
954
  if(typeof opts.maxTimeMS == 'number') {
945
955
  command.maxTimeMS = opts.maxTimeMS;
946
956
  } else if(self.s.cmd && typeof self.s.cmd.maxTimeMS == 'number') {
@@ -993,7 +1003,12 @@ define.classMethod('close', {callback: true, promise:true});
993
1003
  * @return {Cursor}
994
1004
  */
995
1005
  Cursor.prototype.map = function(transform) {
996
- this.cursorState.transforms = { doc: transform };
1006
+ if(this.cursorState.transforms && this.cursorState.transforms.doc) {
1007
+ var oldTransform = this.cursorState.transforms.doc;
1008
+ this.cursorState.transforms.doc = function (doc) { return transform(oldTransform(doc)); };
1009
+ } else {
1010
+ this.cursorState.transforms = { doc: transform };
1011
+ }
997
1012
  return this;
998
1013
  }
999
1014
 
package/lib/db.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  var EventEmitter = require('events').EventEmitter
4
+ , authenticate = require('./authenticate')
4
5
  , inherits = require('util').inherits
5
6
  , getSingleProperty = require('./utils').getSingleProperty
6
7
  , shallowClone = require('./utils').shallowClone
@@ -461,6 +462,7 @@ Db.prototype.collection = function(name, options, callback) {
461
462
  if(callback) callback(null, collection);
462
463
  return collection;
463
464
  } catch(err) {
465
+ // if(err instanceof MongoError && callback) return callback(err);
464
466
  if(callback) return callback(err);
465
467
  throw err;
466
468
  }
@@ -1469,74 +1471,6 @@ Db.prototype.removeUser = function(username, options, callback) {
1469
1471
  });
1470
1472
  };
1471
1473
 
1472
- var authenticate = function(self, username, password, options, callback) {
1473
- // Did the user destroy the topology
1474
- if(self.serverConfig && self.serverConfig.isDestroyed()) return callback(new MongoError('topology was destroyed'));
1475
-
1476
- // the default db to authenticate against is 'self'
1477
- // if authententicate is called from a retry context, it may be another one, like admin
1478
- var authdb = options.dbName ? options.dbName : self.databaseName;
1479
- authdb = self.authSource ? self.authSource : authdb;
1480
- authdb = options.authdb ? options.authdb : authdb;
1481
- authdb = options.authSource ? options.authSource : authdb;
1482
-
1483
- // Callback
1484
- var _callback = function(err, result) {
1485
- if(self.listeners('authenticated').length > 0) {
1486
- self.emit('authenticated', err, result);
1487
- }
1488
-
1489
- // Return to caller
1490
- handleCallback(callback, err, result);
1491
- }
1492
-
1493
- // authMechanism
1494
- var authMechanism = options.authMechanism || '';
1495
- authMechanism = authMechanism.toUpperCase();
1496
-
1497
- // If classic auth delegate to auth command
1498
- if(authMechanism == 'MONGODB-CR') {
1499
- self.s.topology.auth('mongocr', authdb, username, password, function(err) {
1500
- if(err) return handleCallback(callback, err, false);
1501
- _callback(null, true);
1502
- });
1503
- } else if(authMechanism == 'PLAIN') {
1504
- self.s.topology.auth('plain', authdb, username, password, function(err) {
1505
- if(err) return handleCallback(callback, err, false);
1506
- _callback(null, true);
1507
- });
1508
- } else if(authMechanism == 'MONGODB-X509') {
1509
- self.s.topology.auth('x509', authdb, username, password, function(err) {
1510
- if(err) return handleCallback(callback, err, false);
1511
- _callback(null, true);
1512
- });
1513
- } else if(authMechanism == 'SCRAM-SHA-1') {
1514
- self.s.topology.auth('scram-sha-1', authdb, username, password, function(err) {
1515
- if(err) return handleCallback(callback, err, false);
1516
- _callback(null, true);
1517
- });
1518
- } else if(authMechanism == 'GSSAPI') {
1519
- if(process.platform == 'win32') {
1520
- self.s.topology.auth('sspi', authdb, username, password, options, function(err) {
1521
- if(err) return handleCallback(callback, err, false);
1522
- _callback(null, true);
1523
- });
1524
- } else {
1525
- self.s.topology.auth('gssapi', authdb, username, password, options, function(err) {
1526
- if(err) return handleCallback(callback, err, false);
1527
- _callback(null, true);
1528
- });
1529
- }
1530
- } else if(authMechanism == 'DEFAULT') {
1531
- self.s.topology.auth('default', authdb, username, password, function(err) {
1532
- if(err) return handleCallback(callback, err, false);
1533
- _callback(null, true);
1534
- });
1535
- } else {
1536
- handleCallback(callback, MongoError.create({message: f("authentication mechanism %s not supported", options.authMechanism), driver:true}));
1537
- }
1538
- }
1539
-
1540
1474
  /**
1541
1475
  * Authenticate a user against the server.
1542
1476
  * @method
@@ -1546,44 +1480,11 @@ var authenticate = function(self, username, password, options, callback) {
1546
1480
  * @param {string} [options.authMechanism=MONGODB-CR] The authentication mechanism to use, GSSAPI, MONGODB-CR, MONGODB-X509, PLAIN
1547
1481
  * @param {Db~resultCallback} [callback] The command result callback
1548
1482
  * @return {Promise} returns Promise if no callback passed
1483
+ * @deprecated This method will no longer be available in the next major release 3.x as MongoDB 3.6 will only allow auth against users in the admin db and will no longer allow multiple credentials on a socket. Please authenticate using MongoClient.connect with auth credentials.
1549
1484
  */
1550
1485
  Db.prototype.authenticate = function(username, password, options, callback) {
1551
- if(typeof options == 'function') callback = options, options = {};
1552
- var self = this;
1553
- // Shallow copy the options
1554
- options = shallowClone(options);
1555
-
1556
- // Set default mechanism
1557
- if(!options.authMechanism) {
1558
- options.authMechanism = 'DEFAULT';
1559
- } else if(options.authMechanism != 'GSSAPI'
1560
- && options.authMechanism != 'DEFAULT'
1561
- && options.authMechanism != 'MONGODB-CR'
1562
- && options.authMechanism != 'MONGODB-X509'
1563
- && options.authMechanism != 'SCRAM-SHA-1'
1564
- && options.authMechanism != 'PLAIN') {
1565
- return handleCallback(callback, MongoError.create({message: "only DEFAULT, GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR is supported by authMechanism", driver:true}));
1566
- }
1567
-
1568
- // If we have a callback fallback
1569
- if(typeof callback == 'function') return authenticate(self, username, password, options, function(err, r) {
1570
- // Support failed auth method
1571
- if(err && err.message && err.message.indexOf('saslStart') != -1) err.code = 59;
1572
- // Reject error
1573
- if(err) return callback(err, r);
1574
- callback(null, r);
1575
- });
1576
-
1577
- // Return a promise
1578
- return new this.s.promiseLibrary(function(resolve, reject) {
1579
- authenticate(self, username, password, options, function(err, r) {
1580
- // Support failed auth method
1581
- if(err && err.message && err.message.indexOf('saslStart') != -1) err.code = 59;
1582
- // Reject error
1583
- if(err) return reject(err);
1584
- resolve(r);
1585
- });
1586
- });
1486
+ console.warn("Db.prototype.authenticate method will no longer be available in the next major release 3.x as MongoDB 3.6 will only allow auth against users in the admin db and will no longer allow multiple credentials on a socket. Please authenticate using MongoClient.connect with auth credentials.");
1487
+ return authenticate.apply(this, [this].concat(Array.prototype.slice.call(arguments)));
1587
1488
  };
1588
1489
 
1589
1490
  define.classMethod('authenticate', {callback: true, promise:true});
@@ -427,20 +427,23 @@ var writeFile = function(self, file, callback) {
427
427
 
428
428
  // Write a chunk
429
429
  var writeChunk = function() {
430
- fs.read(file, self.chunkSize, offset, 'binary', function(err, data, bytesRead) {
430
+ // Allocate the buffer
431
+ var _buffer = new Buffer(self.chunkSize);
432
+ // Read the file
433
+ fs.read(file, _buffer, 0, _buffer.length, offset, function(err, bytesRead, data) {
431
434
  if(err) return callback(err, self);
432
435
 
433
436
  offset = offset + bytesRead;
434
437
 
435
438
  // Create a new chunk for the data
436
439
  var chunk = new Chunk(self, {n:index++}, self.writeConcern);
437
- chunk.write(data, function(err, chunk) {
440
+ chunk.write(data.slice(0, bytesRead), function(err, chunk) {
438
441
  if(err) return callback(err, self);
439
442
 
440
443
  chunk.save({}, function(err) {
441
444
  if(err) return callback(err, self);
442
445
 
443
- self.position = self.position + data.length;
446
+ self.position = self.position + bytesRead;
444
447
 
445
448
  // Point to current chunk
446
449
  self.currentChunk = chunk;
@@ -298,15 +298,27 @@ function init(self) {
298
298
  return;
299
299
  }
300
300
 
301
- self.s.cursor = self.s.chunks.find({ files_id: doc._id }).sort({ n: 1 });
301
+ self.s.bytesToSkip = handleStartOption(self, doc, self.s.options);
302
+
303
+ var filter = { files_id: doc._id };
304
+
305
+ // Currently (MongoDB 3.4.4) skip function does not support the index,
306
+ // it needs to retrieve all the documents first and then skip them. (CS-25811)
307
+ // As work around we use $gte on the "n" field.
308
+ if (self.s.options && self.s.options.start != null){
309
+ var skip = Math.floor(self.s.options.start / doc.chunkSize);
310
+ if (skip > 0){
311
+ filter["n"] = {"$gte": skip};
312
+ }
313
+ }
314
+ self.s.cursor = self.s.chunks.find(filter).sort({ n: 1 });
315
+
302
316
  if (self.s.readPreference) {
303
317
  self.s.cursor.setReadPreference(self.s.readPreference);
304
318
  }
305
319
 
306
320
  self.s.expectedEnd = Math.ceil(doc.length / doc.chunkSize);
307
321
  self.s.file = doc;
308
- self.s.bytesToSkip = handleStartOption(self, doc, self.s.cursor,
309
- self.s.options);
310
322
  self.s.bytesToTrim = handleEndOption(self, doc, self.s.cursor,
311
323
  self.s.options);
312
324
  self.emit('file', doc);
@@ -336,11 +348,11 @@ function waitForFile(_this, callback) {
336
348
  * @ignore
337
349
  */
338
350
 
339
- function handleStartOption(stream, doc, cursor, options) {
351
+ function handleStartOption(stream, doc, options) {
340
352
  if (options && options.start != null) {
341
353
  if (options.start > doc.length) {
342
354
  throw new Error('Stream start (' + options.start + ') must not be ' +
343
- 'more than the length of the file (' + doc.length +')')
355
+ 'more than the length of the file (' + doc.length +')');
344
356
  }
345
357
  if (options.start < 0) {
346
358
  throw new Error('Stream start (' + options.start + ') must not be ' +
@@ -351,8 +363,6 @@ function handleStartOption(stream, doc, cursor, options) {
351
363
  'greater than stream end (' + options.end + ')');
352
364
  }
353
365
 
354
- cursor.skip(Math.floor(options.start / doc.chunkSize));
355
-
356
366
  stream.s.bytesRead = Math.floor(options.start / doc.chunkSize) *
357
367
  doc.chunkSize;
358
368
  stream.s.expected = Math.floor(options.start / doc.chunkSize);
@@ -33,6 +33,8 @@ function GridFSBucketWriteStream(bucket, filename, options) {
33
33
  this.filename = filename;
34
34
  this.files = bucket.s._filesCollection;
35
35
  this.options = options;
36
+ // Signals the write is all done
37
+ this.done = false;
36
38
 
37
39
  this.id = options.id ? options.id : core.BSON.ObjectId();
38
40
  this.chunkSizeBytes = this.options.chunkSizeBytes;
@@ -252,9 +254,13 @@ function checkChunksIndex(_this, callback) {
252
254
  */
253
255
 
254
256
  function checkDone(_this, callback) {
257
+ if(_this.done) return true;
255
258
  if (_this.state.streamEnd &&
256
259
  _this.state.outstandingRequests === 0 &&
257
260
  !_this.state.errored) {
261
+ // Set done so we dont' trigger duplicate createFilesDoc
262
+ _this.done = true;
263
+ // Create a new files doc
258
264
  var filesDoc = createFilesDoc(_this.id, _this.length, _this.chunkSizeBytes,
259
265
  _this.md5.digest('hex'), _this.filename, _this.options.contentType,
260
266
  _this.options.aliases, _this.options.metadata);
@@ -421,6 +427,7 @@ function doWrite(_this, chunk, encoding, callback) {
421
427
  }
422
428
  --_this.state.outstandingRequests;
423
429
  --outstandingRequests;
430
+
424
431
  if (!outstandingRequests) {
425
432
  _this.emit('drain', doc);
426
433
  callback && callback();