mongodb 3.3.0-beta1 → 3.3.0-beta2
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/lib/aggregation_cursor.js +3 -1
- package/lib/change_stream.js +183 -71
- package/lib/collection.js +8 -9
- package/lib/command_cursor.js +6 -4
- package/lib/core/connection/connect.js +1 -1
- package/lib/core/connection/pool.js +66 -41
- package/lib/core/cursor.js +70 -60
- package/lib/core/error.js +24 -1
- package/lib/core/sdam/server.js +84 -9
- package/lib/core/sdam/server_description.js +14 -0
- package/lib/core/sdam/topology.js +17 -4
- package/lib/core/sdam/topology_description.js +6 -14
- package/lib/core/topologies/mongos.js +1 -1
- package/lib/core/topologies/replset.js +1 -1
- package/lib/core/topologies/server.js +36 -1
- package/lib/core/utils.js +38 -1
- package/lib/core/wireprotocol/command.js +2 -2
- package/lib/cursor.js +7 -5
- package/lib/db.js +7 -1
- package/lib/error.js +10 -8
- package/lib/mongo_client.js +9 -13
- package/lib/operations/aggregate.js +17 -9
- package/lib/operations/close.js +47 -0
- package/lib/operations/collection_ops.js +4 -0
- package/lib/operations/command.js +2 -1
- package/lib/operations/command_v2.js +43 -0
- package/lib/operations/connect.js +83 -9
- package/lib/operations/create_collection.js +1 -0
- package/lib/operations/distinct.js +20 -21
- package/lib/operations/drop.js +1 -0
- package/lib/operations/execute_operation.js +81 -2
- package/lib/operations/explain.js +0 -4
- package/lib/operations/operation.js +3 -1
- package/package.json +1 -1
- package/lib/operations/mongo_client_ops.js +0 -731
|
@@ -56,10 +56,12 @@ const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
|
|
56
56
|
* @fires AggregationCursor#readable
|
|
57
57
|
* @return {AggregationCursor} an AggregationCursor instance.
|
|
58
58
|
*/
|
|
59
|
-
var AggregationCursor = function(
|
|
59
|
+
var AggregationCursor = function(topology, ns, cmd, options) {
|
|
60
60
|
CoreCursor.apply(this, Array.prototype.slice.call(arguments, 0));
|
|
61
61
|
var state = AggregationCursor.INIT;
|
|
62
62
|
var streamOptions = {};
|
|
63
|
+
const bson = topology.s.bson;
|
|
64
|
+
const topologyOptions = topology.s.options;
|
|
63
65
|
|
|
64
66
|
// MaxTimeMS
|
|
65
67
|
var maxTimeMS = null;
|
package/lib/change_stream.js
CHANGED
|
@@ -5,8 +5,14 @@ const isResumableError = require('./error').isResumableError;
|
|
|
5
5
|
const MongoError = require('./core').MongoError;
|
|
6
6
|
const ReadConcern = require('./read_concern');
|
|
7
7
|
const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
|
8
|
+
const Cursor = require('./cursor');
|
|
9
|
+
const relayEvents = require('./core/utils').relayEvents;
|
|
10
|
+
const maxWireVersion = require('./core/utils').maxWireVersion;
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
const CHANGE_STREAM_OPTIONS = ['resumeAfter', 'startAfter', 'startAtOperationTime', 'fullDocument'];
|
|
13
|
+
const CURSOR_OPTIONS = ['batchSize', 'maxAwaitTimeMS', 'collation', 'readPreference'].concat(
|
|
14
|
+
CHANGE_STREAM_OPTIONS
|
|
15
|
+
);
|
|
10
16
|
|
|
11
17
|
const CHANGE_DOMAIN_TYPES = {
|
|
12
18
|
COLLECTION: Symbol('Collection'),
|
|
@@ -14,26 +20,45 @@ const CHANGE_DOMAIN_TYPES = {
|
|
|
14
20
|
CLUSTER: Symbol('Cluster')
|
|
15
21
|
};
|
|
16
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @typedef ResumeToken
|
|
25
|
+
* @description Represents the logical starting point for a new or resuming {@link ChangeStream} on the server.
|
|
26
|
+
* @see https://docs.mongodb.com/master/changeStreams/#change-stream-resume-token
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef OperationTime
|
|
31
|
+
* @description Represents a specific point in time on a server. Can be retrieved by using {@link Db#command}
|
|
32
|
+
* @see https://docs.mongodb.com/manual/reference/method/db.runCommand/#response
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @typedef ChangeStreamOptions
|
|
37
|
+
* @description Options that can be passed to a ChangeStream. Note that startAfter, resumeAfter, and startAtOperationTime are all mutually exclusive, and the server will error if more than one is specified.
|
|
38
|
+
* @property {string} [fullDocument='default'] Allowed values: ‘default’, ‘updateLookup’. When set to ‘updateLookup’, the change stream will include both a delta describing the changes to the document, as well as a copy of the entire document that was changed from some time after the change occurred.
|
|
39
|
+
* @property {number} [maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a change stream query.
|
|
40
|
+
* @property {ResumeToken} [resumeAfter] Allows you to start a changeStream after a specified event. See {@link https://docs.mongodb.com/master/changeStreams/#resumeafter-for-change-streams|ChangeStream documentation}.
|
|
41
|
+
* @property {ResumeToken} [startAfter] Similar to resumeAfter, but will allow you to start after an invalidated event. See {@link https://docs.mongodb.com/master/changeStreams/#startafter-for-change-streams|ChangeStream documentation}.
|
|
42
|
+
* @property {OperationTime} [startAtOperationTime] Will start the changeStream after the specified operationTime.
|
|
43
|
+
* @property {number} [batchSize] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
44
|
+
* @property {object} [collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
45
|
+
* @property {ReadPreference} [readPreference] The read preference. Defaults to the read preference of the database or collection. See {@link https://docs.mongodb.com/manual/reference/read-preference|read preference documentation}.
|
|
46
|
+
*/
|
|
47
|
+
|
|
17
48
|
/**
|
|
18
49
|
* Creates a new Change Stream instance. Normally created using {@link Collection#watch|Collection.watch()}.
|
|
19
50
|
* @class ChangeStream
|
|
20
51
|
* @since 3.0.0
|
|
21
52
|
* @param {(MongoClient|Db|Collection)} changeDomain The domain against which to create the change stream
|
|
22
53
|
* @param {Array} pipeline An array of {@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents
|
|
23
|
-
* @param {
|
|
24
|
-
* @param {string} [options.fullDocument='default'] Allowed values: ‘default’, ‘updateLookup’. When set to ‘updateLookup’, the change stream will include both a delta describing the changes to the document, as well as a copy of the entire document that was changed from some time after the change occurred.
|
|
25
|
-
* @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a change stream query
|
|
26
|
-
* @param {object} [options.resumeAfter] Specifies the logical starting point for the new change stream. This should be the _id field from a previously returned change stream document.
|
|
27
|
-
* @param {number} [options.batchSize] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
28
|
-
* @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
29
|
-
* @param {ReadPreference} [options.readPreference] The read preference. Defaults to the read preference of the database or collection. See {@link https://docs.mongodb.com/manual/reference/read-preference|read preference documentation}.
|
|
54
|
+
* @param {ChangeStreamOptions} [options] Optional settings
|
|
30
55
|
* @fires ChangeStream#close
|
|
31
56
|
* @fires ChangeStream#change
|
|
32
57
|
* @fires ChangeStream#end
|
|
33
58
|
* @fires ChangeStream#error
|
|
59
|
+
* @fires ChangeStream#resumeTokenChanged
|
|
34
60
|
* @return {ChangeStream} a ChangeStream instance.
|
|
35
61
|
*/
|
|
36
|
-
|
|
37
62
|
class ChangeStream extends EventEmitter {
|
|
38
63
|
constructor(changeDomain, pipeline, options) {
|
|
39
64
|
super();
|
|
@@ -69,16 +94,8 @@ class ChangeStream extends EventEmitter {
|
|
|
69
94
|
this.options.readPreference = changeDomain.s.readPreference;
|
|
70
95
|
}
|
|
71
96
|
|
|
72
|
-
// We need to get the operationTime as early as possible
|
|
73
|
-
const isMaster = this.topology.lastIsMaster();
|
|
74
|
-
if (!isMaster) {
|
|
75
|
-
throw new MongoError('Topology does not have an ismaster yet.');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
this.operationTime = isMaster.operationTime;
|
|
79
|
-
|
|
80
97
|
// Create contained Change Stream cursor
|
|
81
|
-
this.cursor = createChangeStreamCursor(this);
|
|
98
|
+
this.cursor = createChangeStreamCursor(this, options);
|
|
82
99
|
|
|
83
100
|
// Listen for any `change` listeners being added to ChangeStream
|
|
84
101
|
this.on('newListener', eventName => {
|
|
@@ -97,6 +114,15 @@ class ChangeStream extends EventEmitter {
|
|
|
97
114
|
});
|
|
98
115
|
}
|
|
99
116
|
|
|
117
|
+
/**
|
|
118
|
+
* @property {ResumeToken} resumeToken
|
|
119
|
+
* The cached resume token that will be used to resume
|
|
120
|
+
* after the most recently returned change.
|
|
121
|
+
*/
|
|
122
|
+
get resumeToken() {
|
|
123
|
+
return this.cursor.resumeToken;
|
|
124
|
+
}
|
|
125
|
+
|
|
100
126
|
/**
|
|
101
127
|
* Check if there is any document still available in the Change Stream
|
|
102
128
|
* @function ChangeStream.prototype.hasNext
|
|
@@ -215,13 +241,114 @@ class ChangeStream extends EventEmitter {
|
|
|
215
241
|
}
|
|
216
242
|
}
|
|
217
243
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
244
|
+
class ChangeStreamCursor extends Cursor {
|
|
245
|
+
constructor(topology, ns, cmd, options) {
|
|
246
|
+
// TODO: spread will help a lot here
|
|
247
|
+
super(topology, ns, cmd, options);
|
|
248
|
+
|
|
249
|
+
options = options || {};
|
|
250
|
+
this._resumeToken = null;
|
|
251
|
+
this.startAtOperationTime = options.startAtOperationTime;
|
|
252
|
+
|
|
253
|
+
if (options.startAfter) {
|
|
254
|
+
this.resumeToken = options.startAfter;
|
|
255
|
+
} else if (options.resumeAfter) {
|
|
256
|
+
this.resumeToken = options.resumeAfter;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
set resumeToken(token) {
|
|
261
|
+
this._resumeToken = token;
|
|
262
|
+
this.emit('resumeTokenChanged', token);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
get resumeToken() {
|
|
266
|
+
return this._resumeToken;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
get resumeOptions() {
|
|
270
|
+
const result = {};
|
|
271
|
+
for (const optionName of CURSOR_OPTIONS) {
|
|
272
|
+
if (this.options[optionName]) result[optionName] = this.options[optionName];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (this.resumeToken || this.startAtOperationTime) {
|
|
276
|
+
['resumeAfter', 'startAfter', 'startAtOperationTime'].forEach(key => delete result[key]);
|
|
277
|
+
|
|
278
|
+
if (this.resumeToken) {
|
|
279
|
+
result.resumeAfter = this.resumeToken;
|
|
280
|
+
} else if (this.startAtOperationTime && maxWireVersion(this.server) >= 7) {
|
|
281
|
+
result.startAtOperationTime = this.startAtOperationTime;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return result;
|
|
222
286
|
}
|
|
223
287
|
|
|
224
|
-
|
|
288
|
+
_initializeCursor(callback) {
|
|
289
|
+
super._initializeCursor((err, result) => {
|
|
290
|
+
if (err) {
|
|
291
|
+
callback(err, null);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const response = result.documents[0];
|
|
296
|
+
|
|
297
|
+
if (
|
|
298
|
+
this.startAtOperationTime == null &&
|
|
299
|
+
this.resumeAfter == null &&
|
|
300
|
+
this.startAfter == null &&
|
|
301
|
+
maxWireVersion(this.server) >= 7
|
|
302
|
+
) {
|
|
303
|
+
this.startAtOperationTime = response.operationTime;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const cursor = response.cursor;
|
|
307
|
+
if (cursor.postBatchResumeToken) {
|
|
308
|
+
this.cursorState.postBatchResumeToken = cursor.postBatchResumeToken;
|
|
309
|
+
|
|
310
|
+
if (cursor.firstBatch.length === 0) {
|
|
311
|
+
this.resumeToken = cursor.postBatchResumeToken;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
this.emit('response');
|
|
316
|
+
callback(err, result);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
_getMore(callback) {
|
|
321
|
+
super._getMore((err, response) => {
|
|
322
|
+
if (err) {
|
|
323
|
+
callback(err, null);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const cursor = response.cursor;
|
|
328
|
+
if (cursor.postBatchResumeToken) {
|
|
329
|
+
this.cursorState.postBatchResumeToken = cursor.postBatchResumeToken;
|
|
330
|
+
|
|
331
|
+
if (cursor.nextBatch.length === 0) {
|
|
332
|
+
this.resumeToken = cursor.postBatchResumeToken;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
this.emit('response');
|
|
337
|
+
callback(err, response);
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* @event ChangeStreamCursor#response
|
|
344
|
+
* internal event DO NOT USE
|
|
345
|
+
* @ignore
|
|
346
|
+
*/
|
|
347
|
+
|
|
348
|
+
// Create a new change stream cursor based on self's configuration
|
|
349
|
+
var createChangeStreamCursor = function(self, options) {
|
|
350
|
+
const changeStreamCursor = buildChangeStreamAggregationCommand(self, options);
|
|
351
|
+
relayEvents(changeStreamCursor, self, ['resumeTokenChanged', 'end', 'close']);
|
|
225
352
|
|
|
226
353
|
/**
|
|
227
354
|
* Fired for each new matching change in the specified namespace. Attaching a `change`
|
|
@@ -243,9 +370,6 @@ var createChangeStreamCursor = function(self) {
|
|
|
243
370
|
* @event ChangeStream#close
|
|
244
371
|
* @type {null}
|
|
245
372
|
*/
|
|
246
|
-
changeStreamCursor.on('close', function() {
|
|
247
|
-
self.emit('close');
|
|
248
|
-
});
|
|
249
373
|
|
|
250
374
|
/**
|
|
251
375
|
* Change stream end event
|
|
@@ -253,9 +377,13 @@ var createChangeStreamCursor = function(self) {
|
|
|
253
377
|
* @event ChangeStream#end
|
|
254
378
|
* @type {null}
|
|
255
379
|
*/
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Emitted each time the change stream stores a new resume token.
|
|
383
|
+
*
|
|
384
|
+
* @event ChangeStream#resumeTokenChanged
|
|
385
|
+
* @type {ResumeToken}
|
|
386
|
+
*/
|
|
259
387
|
|
|
260
388
|
/**
|
|
261
389
|
* Fired when the stream encounters an error.
|
|
@@ -277,44 +405,26 @@ var createChangeStreamCursor = function(self) {
|
|
|
277
405
|
return changeStreamCursor;
|
|
278
406
|
};
|
|
279
407
|
|
|
280
|
-
function
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
return (
|
|
287
|
-
isMaster.maxWireVersion && isMaster.maxWireVersion >= 7 && self.options.startAtOperationTime
|
|
288
|
-
);
|
|
408
|
+
function applyKnownOptions(target, source, optionNames) {
|
|
409
|
+
optionNames.forEach(name => {
|
|
410
|
+
if (source[name]) {
|
|
411
|
+
target[name] = source[name];
|
|
412
|
+
}
|
|
413
|
+
});
|
|
289
414
|
}
|
|
290
415
|
|
|
291
|
-
var buildChangeStreamAggregationCommand = function(self) {
|
|
416
|
+
var buildChangeStreamAggregationCommand = function(self, options) {
|
|
417
|
+
options = options || {};
|
|
292
418
|
const topology = self.topology;
|
|
293
419
|
const namespace = self.namespace;
|
|
294
420
|
const pipeline = self.pipeline;
|
|
295
|
-
const options = self.options;
|
|
296
421
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
const resumeToken = getResumeToken(self);
|
|
302
|
-
const startAtOperationTime = getStartAtOperationTime(self);
|
|
303
|
-
if (resumeToken) {
|
|
304
|
-
changeStreamStageOptions.resumeAfter = resumeToken;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (startAtOperationTime) {
|
|
308
|
-
changeStreamStageOptions.startAtOperationTime = startAtOperationTime;
|
|
309
|
-
}
|
|
422
|
+
const changeStreamStageOptions = { fullDocument: options.fullDocument || 'default' };
|
|
423
|
+
applyKnownOptions(changeStreamStageOptions, options, CHANGE_STREAM_OPTIONS);
|
|
310
424
|
|
|
311
425
|
// Map cursor options
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (options[optionName]) {
|
|
315
|
-
cursorOptions[optionName] = options[optionName];
|
|
316
|
-
}
|
|
317
|
-
});
|
|
426
|
+
const cursorOptions = { cursorFactory: ChangeStreamCursor };
|
|
427
|
+
applyKnownOptions(cursorOptions, options, CURSOR_OPTIONS);
|
|
318
428
|
|
|
319
429
|
if (self.type === CHANGE_DOMAIN_TYPES.CLUSTER) {
|
|
320
430
|
changeStreamStageOptions.allChangesForCluster = true;
|
|
@@ -377,6 +487,7 @@ function processNewChange(args) {
|
|
|
377
487
|
: changeStream.promiseLibrary.reject(error);
|
|
378
488
|
}
|
|
379
489
|
|
|
490
|
+
const cursor = changeStream.cursor;
|
|
380
491
|
const topology = changeStream.topology;
|
|
381
492
|
const options = changeStream.cursor.options;
|
|
382
493
|
|
|
@@ -384,11 +495,6 @@ function processNewChange(args) {
|
|
|
384
495
|
if (isResumableError(error) && !changeStream.attemptingResume) {
|
|
385
496
|
changeStream.attemptingResume = true;
|
|
386
497
|
|
|
387
|
-
if (!(getResumeToken(changeStream) || getStartAtOperationTime(changeStream))) {
|
|
388
|
-
const startAtOperationTime = changeStream.cursor.cursorState.operationTime;
|
|
389
|
-
changeStream.options = Object.assign({ startAtOperationTime }, changeStream.options);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
498
|
// stop listening to all events from old cursor
|
|
393
499
|
['data', 'close', 'end', 'error'].forEach(event =>
|
|
394
500
|
changeStream.cursor.removeAllListeners(event)
|
|
@@ -401,7 +507,7 @@ function processNewChange(args) {
|
|
|
401
507
|
if (eventEmitter) {
|
|
402
508
|
waitForTopologyConnected(topology, { readPreference: options.readPreference }, err => {
|
|
403
509
|
if (err) return changeStream.emit('error', err);
|
|
404
|
-
changeStream.cursor = createChangeStreamCursor(changeStream);
|
|
510
|
+
changeStream.cursor = createChangeStreamCursor(changeStream, cursor.resumeOptions);
|
|
405
511
|
});
|
|
406
512
|
|
|
407
513
|
return;
|
|
@@ -411,7 +517,7 @@ function processNewChange(args) {
|
|
|
411
517
|
waitForTopologyConnected(topology, { readPreference: options.readPreference }, err => {
|
|
412
518
|
if (err) return callback(err, null);
|
|
413
519
|
|
|
414
|
-
changeStream.cursor = createChangeStreamCursor(changeStream);
|
|
520
|
+
changeStream.cursor = createChangeStreamCursor(changeStream, cursor.resumeOptions);
|
|
415
521
|
changeStream.next(callback);
|
|
416
522
|
});
|
|
417
523
|
|
|
@@ -424,7 +530,9 @@ function processNewChange(args) {
|
|
|
424
530
|
resolve();
|
|
425
531
|
});
|
|
426
532
|
})
|
|
427
|
-
.then(
|
|
533
|
+
.then(
|
|
534
|
+
() => (changeStream.cursor = createChangeStreamCursor(changeStream, cursor.resumeOptions))
|
|
535
|
+
)
|
|
428
536
|
.then(() => changeStream.next());
|
|
429
537
|
}
|
|
430
538
|
|
|
@@ -435,9 +543,8 @@ function processNewChange(args) {
|
|
|
435
543
|
|
|
436
544
|
changeStream.attemptingResume = false;
|
|
437
545
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
var noResumeTokenError = new Error(
|
|
546
|
+
if (change && !change._id) {
|
|
547
|
+
const noResumeTokenError = new Error(
|
|
441
548
|
'A change stream document has been received that lacks a resume token (_id).'
|
|
442
549
|
);
|
|
443
550
|
|
|
@@ -446,7 +553,12 @@ function processNewChange(args) {
|
|
|
446
553
|
return changeStream.promiseLibrary.reject(noResumeTokenError);
|
|
447
554
|
}
|
|
448
555
|
|
|
449
|
-
|
|
556
|
+
// cache the resume token
|
|
557
|
+
if (cursor.bufferedCount() === 0 && cursor.cursorState.postBatchResumeToken) {
|
|
558
|
+
cursor.resumeToken = cursor.cursorState.postBatchResumeToken;
|
|
559
|
+
} else {
|
|
560
|
+
cursor.resumeToken = change._id;
|
|
561
|
+
}
|
|
450
562
|
|
|
451
563
|
// Return the change
|
|
452
564
|
if (eventEmitter) return changeStream.emit('change', change);
|
package/lib/collection.js
CHANGED
|
@@ -526,6 +526,8 @@ Collection.prototype.insertMany = function(docs, options, callback) {
|
|
|
526
526
|
*
|
|
527
527
|
* { updateMany: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
|
|
528
528
|
*
|
|
529
|
+
* { updateMany: { filter: {}, update: {$set: {"a.$[i].x": 5}}, arrayFilters: [{ "i.x": 5 }]} }
|
|
530
|
+
*
|
|
529
531
|
* { deleteOne: { filter: {c:1} } }
|
|
530
532
|
*
|
|
531
533
|
* { deleteMany: { filter: {c:1} } }
|
|
@@ -539,6 +541,7 @@ Collection.prototype.insertMany = function(docs, options, callback) {
|
|
|
539
541
|
* @method
|
|
540
542
|
* @param {object[]} operations Bulk operations to perform.
|
|
541
543
|
* @param {object} [options] Optional settings.
|
|
544
|
+
* @param {object[]} [options.arrayFilters] Determines which array elements to modify for update operation in MongoDB 3.6 or higher.
|
|
542
545
|
* @param {(number|string)} [options.w] The write concern.
|
|
543
546
|
* @param {number} [options.wtimeout] The write concern timeout.
|
|
544
547
|
* @param {boolean} [options.j=false] Specify a journal write concern.
|
|
@@ -686,15 +689,7 @@ Collection.prototype.updateOne = function(filter, update, options, callback) {
|
|
|
686
689
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
687
690
|
options = options || {};
|
|
688
691
|
|
|
689
|
-
|
|
690
|
-
if (Array.isArray(update)) {
|
|
691
|
-
for (let i = 0; !err && i < update.length; i++) {
|
|
692
|
-
err = checkForAtomicOperators(update[i]);
|
|
693
|
-
}
|
|
694
|
-
} else {
|
|
695
|
-
err = checkForAtomicOperators(update);
|
|
696
|
-
}
|
|
697
|
-
|
|
692
|
+
const err = checkForAtomicOperators(update);
|
|
698
693
|
if (err) {
|
|
699
694
|
if (typeof callback === 'function') return callback(err);
|
|
700
695
|
return this.s.promiseLibrary.reject(err);
|
|
@@ -1056,6 +1051,10 @@ Collection.prototype.rename = function(newName, options, callback) {
|
|
|
1056
1051
|
*
|
|
1057
1052
|
* @method
|
|
1058
1053
|
* @param {object} [options] Optional settings.
|
|
1054
|
+
* @param {WriteConcern} [options.writeConcern] A full WriteConcern object
|
|
1055
|
+
* @param {(number|string)} [options.w] The write concern
|
|
1056
|
+
* @param {number} [options.wtimeout] The write concern timeout
|
|
1057
|
+
* @param {boolean} [options.j] The journal write concern
|
|
1059
1058
|
* @param {ClientSession} [options.session] optional session to use for this operation
|
|
1060
1059
|
* @param {Collection~resultCallback} [callback] The results callback
|
|
1061
1060
|
* @return {Promise} returns Promise if no callback passed
|
package/lib/command_cursor.js
CHANGED
|
@@ -55,10 +55,12 @@ const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
|
|
55
55
|
* @fires CommandCursor#readable
|
|
56
56
|
* @return {CommandCursor} an CommandCursor instance.
|
|
57
57
|
*/
|
|
58
|
-
var CommandCursor = function(
|
|
58
|
+
var CommandCursor = function(topology, ns, cmd, options) {
|
|
59
59
|
CoreCursor.apply(this, Array.prototype.slice.call(arguments, 0));
|
|
60
60
|
var state = CommandCursor.INIT;
|
|
61
61
|
var streamOptions = {};
|
|
62
|
+
const bson = topology.s.bson;
|
|
63
|
+
const topologyOptions = topology.s.options;
|
|
62
64
|
|
|
63
65
|
// MaxTimeMS
|
|
64
66
|
var maxTimeMS = null;
|
|
@@ -150,14 +152,14 @@ var methodsToInherit = [
|
|
|
150
152
|
'kill',
|
|
151
153
|
'setCursorBatchSize',
|
|
152
154
|
'_find',
|
|
153
|
-
'
|
|
155
|
+
'_initializeCursor',
|
|
156
|
+
'_getMore',
|
|
154
157
|
'_killcursor',
|
|
155
158
|
'isDead',
|
|
156
159
|
'explain',
|
|
157
160
|
'isNotified',
|
|
158
161
|
'isKilled',
|
|
159
|
-
'_endSession'
|
|
160
|
-
'_initImplicitSession'
|
|
162
|
+
'_endSession'
|
|
161
163
|
];
|
|
162
164
|
|
|
163
165
|
// Only inherit the types we need
|
|
@@ -278,7 +278,7 @@ function makeConnection(family, options, _callback) {
|
|
|
278
278
|
socket.setTimeout(connectionTimeout);
|
|
279
279
|
socket.setNoDelay(noDelay);
|
|
280
280
|
|
|
281
|
-
const errorEvents = ['error', 'close', 'timeout', 'parseError'
|
|
281
|
+
const errorEvents = ['error', 'close', 'timeout', 'parseError'];
|
|
282
282
|
function errorHandler(eventName) {
|
|
283
283
|
return err => {
|
|
284
284
|
errorEvents.forEach(event => socket.removeAllListeners(event));
|
|
@@ -19,6 +19,7 @@ const apm = require('./apm');
|
|
|
19
19
|
const Buffer = require('safe-buffer').Buffer;
|
|
20
20
|
const connect = require('./connect');
|
|
21
21
|
const updateSessionFromResponse = require('../sessions').updateSessionFromResponse;
|
|
22
|
+
const eachAsync = require('../utils').eachAsync;
|
|
22
23
|
|
|
23
24
|
var DISCONNECTED = 'disconnected';
|
|
24
25
|
var CONNECTING = 'connecting';
|
|
@@ -26,6 +27,15 @@ var CONNECTED = 'connected';
|
|
|
26
27
|
var DESTROYING = 'destroying';
|
|
27
28
|
var DESTROYED = 'destroyed';
|
|
28
29
|
|
|
30
|
+
const CONNECTION_EVENTS = new Set([
|
|
31
|
+
'error',
|
|
32
|
+
'close',
|
|
33
|
+
'timeout',
|
|
34
|
+
'parseError',
|
|
35
|
+
'connect',
|
|
36
|
+
'message'
|
|
37
|
+
]);
|
|
38
|
+
|
|
29
39
|
var _id = 0;
|
|
30
40
|
|
|
31
41
|
/**
|
|
@@ -198,6 +208,19 @@ Object.defineProperty(Pool.prototype, 'socketTimeout', {
|
|
|
198
208
|
}
|
|
199
209
|
});
|
|
200
210
|
|
|
211
|
+
// clears all pool state
|
|
212
|
+
function resetPoolState(pool) {
|
|
213
|
+
pool.inUseConnections = [];
|
|
214
|
+
pool.availableConnections = [];
|
|
215
|
+
pool.connectingConnections = 0;
|
|
216
|
+
pool.executing = false;
|
|
217
|
+
pool.reconnectConnection = null;
|
|
218
|
+
pool.numberOfConsecutiveTimeouts = 0;
|
|
219
|
+
pool.connectionIndex = 0;
|
|
220
|
+
pool.retriesLeft = pool.options.reconnectTries;
|
|
221
|
+
pool.reconnectId = null;
|
|
222
|
+
}
|
|
223
|
+
|
|
201
224
|
function stateTransition(self, newState) {
|
|
202
225
|
var legalTransitions = {
|
|
203
226
|
disconnected: [CONNECTING, DESTROYING, DISCONNECTED],
|
|
@@ -631,43 +654,30 @@ Pool.prototype.unref = function() {
|
|
|
631
654
|
});
|
|
632
655
|
};
|
|
633
656
|
|
|
634
|
-
// Events
|
|
635
|
-
var events = ['error', 'close', 'timeout', 'parseError', 'connect', 'message'];
|
|
636
|
-
|
|
637
657
|
// Destroy the connections
|
|
638
658
|
function destroy(self, connections, options, callback) {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
// Zero out all connections
|
|
647
|
-
self.inUseConnections = [];
|
|
648
|
-
self.availableConnections = [];
|
|
649
|
-
self.connectingConnections = 0;
|
|
659
|
+
eachAsync(
|
|
660
|
+
connections,
|
|
661
|
+
(conn, cb) => {
|
|
662
|
+
for (const eventName of CONNECTION_EVENTS) {
|
|
663
|
+
conn.removeAllListeners(eventName);
|
|
664
|
+
}
|
|
650
665
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
666
|
+
conn.destroy(options, cb);
|
|
667
|
+
},
|
|
668
|
+
err => {
|
|
669
|
+
if (err) {
|
|
670
|
+
if (typeof callback === 'function') callback(err, null);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
657
673
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
674
|
+
resetPoolState(self);
|
|
675
|
+
self.queue = [];
|
|
662
676
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
for (var i = 0; i < events.length; i++) {
|
|
666
|
-
conn.removeAllListeners(events[i]);
|
|
677
|
+
stateTransition(self, DESTROYED);
|
|
678
|
+
if (typeof callback === 'function') callback(null, null);
|
|
667
679
|
}
|
|
668
|
-
|
|
669
|
-
conn.destroy(options, connectionDestroyed);
|
|
670
|
-
});
|
|
680
|
+
);
|
|
671
681
|
}
|
|
672
682
|
|
|
673
683
|
/**
|
|
@@ -751,19 +761,34 @@ Pool.prototype.destroy = function(force, callback) {
|
|
|
751
761
|
* @param {function} [callback]
|
|
752
762
|
*/
|
|
753
763
|
Pool.prototype.reset = function(callback) {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
764
|
+
const connections = this.availableConnections.concat(this.inUseConnections);
|
|
765
|
+
eachAsync(
|
|
766
|
+
connections,
|
|
767
|
+
(conn, cb) => {
|
|
768
|
+
for (const eventName of CONNECTION_EVENTS) {
|
|
769
|
+
conn.removeAllListeners(eventName);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
conn.destroy({ force: true }, cb);
|
|
773
|
+
},
|
|
774
|
+
err => {
|
|
775
|
+
if (err) {
|
|
776
|
+
if (typeof callback === 'function') {
|
|
777
|
+
callback(err, null);
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
759
781
|
|
|
760
|
-
|
|
761
|
-
// this.connect();
|
|
782
|
+
resetPoolState(this);
|
|
762
783
|
|
|
763
|
-
|
|
764
|
-
|
|
784
|
+
// create an initial connection, and kick off execution again
|
|
785
|
+
_createConnection(this);
|
|
765
786
|
|
|
766
|
-
|
|
787
|
+
if (typeof callback === 'function') {
|
|
788
|
+
callback(null, null);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
);
|
|
767
792
|
};
|
|
768
793
|
|
|
769
794
|
// Prepare the buffer that Pool.prototype.write() uses to send to the server
|