mongodb 3.2.5 → 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/HISTORY.md +0 -10
- package/index.js +4 -4
- package/lib/admin.js +56 -56
- package/lib/aggregation_cursor.js +7 -3
- package/lib/bulk/common.js +18 -13
- package/lib/change_stream.js +196 -89
- package/lib/collection.js +217 -169
- package/lib/command_cursor.js +17 -7
- package/lib/core/auth/auth_provider.js +158 -0
- package/lib/core/auth/defaultAuthProviders.js +29 -0
- package/lib/core/auth/gssapi.js +241 -0
- package/lib/core/auth/mongo_credentials.js +81 -0
- package/lib/core/auth/mongocr.js +51 -0
- package/lib/core/auth/plain.js +35 -0
- package/lib/core/auth/scram.js +293 -0
- package/lib/core/auth/sspi.js +131 -0
- package/lib/core/auth/x509.js +26 -0
- package/lib/core/connection/apm.js +236 -0
- package/lib/core/connection/command_result.js +36 -0
- package/lib/core/connection/commands.js +507 -0
- package/lib/core/connection/connect.js +370 -0
- package/lib/core/connection/connection.js +624 -0
- package/lib/core/connection/logger.js +246 -0
- package/lib/core/connection/msg.js +219 -0
- package/lib/core/connection/pool.js +1285 -0
- package/lib/core/connection/utils.js +57 -0
- package/lib/core/cursor.js +752 -0
- package/lib/core/error.js +186 -0
- package/lib/core/index.js +50 -0
- package/lib/core/sdam/monitoring.js +228 -0
- package/lib/core/sdam/server.js +467 -0
- package/lib/core/sdam/server_description.js +163 -0
- package/lib/core/sdam/server_selectors.js +244 -0
- package/lib/core/sdam/srv_polling.js +135 -0
- package/lib/core/sdam/topology.js +1151 -0
- package/lib/core/sdam/topology_description.js +408 -0
- package/lib/core/sessions.js +711 -0
- package/lib/core/tools/smoke_plugin.js +61 -0
- package/lib/core/topologies/mongos.js +1337 -0
- package/lib/core/topologies/read_preference.js +202 -0
- package/lib/core/topologies/replset.js +1507 -0
- package/lib/core/topologies/replset_state.js +1121 -0
- package/lib/core/topologies/server.js +984 -0
- package/lib/core/topologies/shared.js +453 -0
- package/lib/core/transactions.js +167 -0
- package/lib/core/uri_parser.js +631 -0
- package/lib/core/utils.js +165 -0
- package/lib/core/wireprotocol/command.js +170 -0
- package/lib/core/wireprotocol/compression.js +73 -0
- package/lib/core/wireprotocol/constants.js +13 -0
- package/lib/core/wireprotocol/get_more.js +86 -0
- package/lib/core/wireprotocol/index.js +18 -0
- package/lib/core/wireprotocol/kill_cursors.js +70 -0
- package/lib/core/wireprotocol/query.js +224 -0
- package/lib/core/wireprotocol/shared.js +115 -0
- package/lib/core/wireprotocol/write_command.js +50 -0
- package/lib/cursor.js +40 -46
- package/lib/db.js +141 -95
- package/lib/dynamic_loaders.js +32 -0
- package/lib/error.js +12 -10
- package/lib/gridfs/chunk.js +2 -2
- package/lib/gridfs/grid_store.js +31 -25
- package/lib/gridfs-stream/index.js +4 -4
- package/lib/gridfs-stream/upload.js +1 -1
- package/lib/mongo_client.js +37 -15
- package/lib/operations/add_user.js +96 -0
- package/lib/operations/aggregate.js +24 -13
- package/lib/operations/aggregate_operation.js +127 -0
- package/lib/operations/bulk_write.js +104 -0
- package/lib/operations/close.js +47 -0
- package/lib/operations/collection_ops.js +28 -287
- package/lib/operations/collections.js +55 -0
- package/lib/operations/command.js +120 -0
- package/lib/operations/command_v2.js +43 -0
- package/lib/operations/common_functions.js +372 -0
- package/lib/operations/{mongo_client_ops.js → connect.js} +185 -157
- package/lib/operations/count.js +72 -0
- package/lib/operations/count_documents.js +46 -0
- package/lib/operations/create_collection.js +118 -0
- package/lib/operations/create_index.js +92 -0
- package/lib/operations/create_indexes.js +61 -0
- package/lib/operations/cursor_ops.js +3 -4
- package/lib/operations/db_ops.js +15 -12
- package/lib/operations/delete_many.js +25 -0
- package/lib/operations/delete_one.js +25 -0
- package/lib/operations/distinct.js +85 -0
- package/lib/operations/drop.js +53 -0
- package/lib/operations/drop_index.js +42 -0
- package/lib/operations/drop_indexes.js +23 -0
- package/lib/operations/estimated_document_count.js +33 -0
- package/lib/operations/execute_db_admin_command.js +34 -0
- package/lib/operations/execute_operation.js +165 -0
- package/lib/operations/explain.js +23 -0
- package/lib/operations/find_and_modify.js +98 -0
- package/lib/operations/find_one.js +33 -0
- package/lib/operations/find_one_and_delete.js +16 -0
- package/lib/operations/find_one_and_replace.js +18 -0
- package/lib/operations/find_one_and_update.js +19 -0
- package/lib/operations/geo_haystack_search.js +79 -0
- package/lib/operations/has_next.js +40 -0
- package/lib/operations/index_exists.js +39 -0
- package/lib/operations/index_information.js +23 -0
- package/lib/operations/indexes.js +22 -0
- package/lib/operations/insert_many.js +63 -0
- package/lib/operations/insert_one.js +75 -0
- package/lib/operations/is_capped.js +19 -0
- package/lib/operations/list_indexes.js +66 -0
- package/lib/operations/map_reduce.js +189 -0
- package/lib/operations/next.js +32 -0
- package/lib/operations/operation.js +63 -0
- package/lib/operations/options_operation.js +32 -0
- package/lib/operations/profiling_level.js +31 -0
- package/lib/operations/re_index.js +28 -0
- package/lib/operations/remove_user.js +52 -0
- package/lib/operations/rename.js +61 -0
- package/lib/operations/replace_one.js +47 -0
- package/lib/operations/set_profiling_level.js +48 -0
- package/lib/operations/stats.js +45 -0
- package/lib/operations/to_array.js +68 -0
- package/lib/operations/update_many.js +29 -0
- package/lib/operations/update_one.js +44 -0
- package/lib/operations/validate_collection.js +40 -0
- package/lib/read_concern.js +55 -0
- package/lib/topologies/mongos.js +3 -3
- package/lib/topologies/native_topology.js +22 -2
- package/lib/topologies/replset.js +3 -3
- package/lib/topologies/server.js +4 -4
- package/lib/topologies/topology_base.js +6 -6
- package/lib/url_parser.js +4 -3
- package/lib/utils.js +46 -59
- package/lib/write_concern.js +66 -0
- package/package.json +15 -6
- package/lib/.DS_Store +0 -0
package/lib/change_stream.js
CHANGED
|
@@ -2,9 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
const EventEmitter = require('events');
|
|
4
4
|
const isResumableError = require('./error').isResumableError;
|
|
5
|
-
const MongoError = require('
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const MongoError = require('./core').MongoError;
|
|
6
|
+
const ReadConcern = require('./read_concern');
|
|
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;
|
|
11
|
+
|
|
12
|
+
const CHANGE_STREAM_OPTIONS = ['resumeAfter', 'startAfter', 'startAtOperationTime', 'fullDocument'];
|
|
13
|
+
const CURSOR_OPTIONS = ['batchSize', 'maxAwaitTimeMS', 'collation', 'readPreference'].concat(
|
|
14
|
+
CHANGE_STREAM_OPTIONS
|
|
15
|
+
);
|
|
8
16
|
|
|
9
17
|
const CHANGE_DOMAIN_TYPES = {
|
|
10
18
|
COLLECTION: Symbol('Collection'),
|
|
@@ -12,26 +20,45 @@ const CHANGE_DOMAIN_TYPES = {
|
|
|
12
20
|
CLUSTER: Symbol('Cluster')
|
|
13
21
|
};
|
|
14
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
|
+
|
|
15
48
|
/**
|
|
16
49
|
* Creates a new Change Stream instance. Normally created using {@link Collection#watch|Collection.watch()}.
|
|
17
50
|
* @class ChangeStream
|
|
18
51
|
* @since 3.0.0
|
|
19
52
|
* @param {(MongoClient|Db|Collection)} changeDomain The domain against which to create the change stream
|
|
20
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
|
|
21
|
-
* @param {
|
|
22
|
-
* @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.
|
|
23
|
-
* @param {number} [options.maxAwaitTimeMS] The maximum amount of time for the server to wait on new documents to satisfy a change stream query
|
|
24
|
-
* @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.
|
|
25
|
-
* @param {number} [options.batchSize] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
26
|
-
* @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
27
|
-
* @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
|
|
28
55
|
* @fires ChangeStream#close
|
|
29
56
|
* @fires ChangeStream#change
|
|
30
57
|
* @fires ChangeStream#end
|
|
31
58
|
* @fires ChangeStream#error
|
|
59
|
+
* @fires ChangeStream#resumeTokenChanged
|
|
32
60
|
* @return {ChangeStream} a ChangeStream instance.
|
|
33
61
|
*/
|
|
34
|
-
|
|
35
62
|
class ChangeStream extends EventEmitter {
|
|
36
63
|
constructor(changeDomain, pipeline, options) {
|
|
37
64
|
super();
|
|
@@ -41,28 +68,20 @@ class ChangeStream extends EventEmitter {
|
|
|
41
68
|
|
|
42
69
|
this.pipeline = pipeline || [];
|
|
43
70
|
this.options = options || {};
|
|
44
|
-
|
|
45
|
-
this.namespace =
|
|
71
|
+
|
|
72
|
+
this.namespace =
|
|
73
|
+
changeDomain instanceof MongoClient
|
|
74
|
+
? new MongoDBNamespace('admin')
|
|
75
|
+
: changeDomain.s.namespace;
|
|
46
76
|
|
|
47
77
|
if (changeDomain instanceof Collection) {
|
|
48
78
|
this.type = CHANGE_DOMAIN_TYPES.COLLECTION;
|
|
49
79
|
this.topology = changeDomain.s.db.serverConfig;
|
|
50
|
-
|
|
51
|
-
this.namespace = {
|
|
52
|
-
collection: changeDomain.collectionName,
|
|
53
|
-
database: changeDomain.s.db.databaseName
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
this.cursorNamespace = `${this.namespace.database}.${this.namespace.collection}`;
|
|
57
80
|
} else if (changeDomain instanceof Db) {
|
|
58
81
|
this.type = CHANGE_DOMAIN_TYPES.DATABASE;
|
|
59
|
-
this.namespace = { collection: '', database: changeDomain.databaseName };
|
|
60
|
-
this.cursorNamespace = this.namespace.database;
|
|
61
82
|
this.topology = changeDomain.serverConfig;
|
|
62
83
|
} else if (changeDomain instanceof MongoClient) {
|
|
63
84
|
this.type = CHANGE_DOMAIN_TYPES.CLUSTER;
|
|
64
|
-
this.namespace = { collection: '', database: 'admin' };
|
|
65
|
-
this.cursorNamespace = this.namespace.database;
|
|
66
85
|
this.topology = changeDomain.topology;
|
|
67
86
|
} else {
|
|
68
87
|
throw new TypeError(
|
|
@@ -75,16 +94,8 @@ class ChangeStream extends EventEmitter {
|
|
|
75
94
|
this.options.readPreference = changeDomain.s.readPreference;
|
|
76
95
|
}
|
|
77
96
|
|
|
78
|
-
// We need to get the operationTime as early as possible
|
|
79
|
-
const isMaster = this.topology.lastIsMaster();
|
|
80
|
-
if (!isMaster) {
|
|
81
|
-
throw new MongoError('Topology does not have an ismaster yet.');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
this.operationTime = isMaster.operationTime;
|
|
85
|
-
|
|
86
97
|
// Create contained Change Stream cursor
|
|
87
|
-
this.cursor = createChangeStreamCursor(this);
|
|
98
|
+
this.cursor = createChangeStreamCursor(this, options);
|
|
88
99
|
|
|
89
100
|
// Listen for any `change` listeners being added to ChangeStream
|
|
90
101
|
this.on('newListener', eventName => {
|
|
@@ -103,6 +114,15 @@ class ChangeStream extends EventEmitter {
|
|
|
103
114
|
});
|
|
104
115
|
}
|
|
105
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
|
+
|
|
106
126
|
/**
|
|
107
127
|
* Check if there is any document still available in the Change Stream
|
|
108
128
|
* @function ChangeStream.prototype.hasNext
|
|
@@ -160,6 +180,7 @@ class ChangeStream extends EventEmitter {
|
|
|
160
180
|
|
|
161
181
|
// Tidy up the existing cursor
|
|
162
182
|
var cursor = this.cursor;
|
|
183
|
+
['data', 'close', 'end', 'error'].forEach(event => this.cursor.removeAllListeners(event));
|
|
163
184
|
delete this.cursor;
|
|
164
185
|
return cursor.close(callback);
|
|
165
186
|
}
|
|
@@ -220,13 +241,114 @@ class ChangeStream extends EventEmitter {
|
|
|
220
241
|
}
|
|
221
242
|
}
|
|
222
243
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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);
|
|
227
263
|
}
|
|
228
264
|
|
|
229
|
-
|
|
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;
|
|
286
|
+
}
|
|
287
|
+
|
|
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']);
|
|
230
352
|
|
|
231
353
|
/**
|
|
232
354
|
* Fired for each new matching change in the specified namespace. Attaching a `change`
|
|
@@ -248,9 +370,6 @@ var createChangeStreamCursor = function(self) {
|
|
|
248
370
|
* @event ChangeStream#close
|
|
249
371
|
* @type {null}
|
|
250
372
|
*/
|
|
251
|
-
changeStreamCursor.on('close', function() {
|
|
252
|
-
self.emit('close');
|
|
253
|
-
});
|
|
254
373
|
|
|
255
374
|
/**
|
|
256
375
|
* Change stream end event
|
|
@@ -258,9 +377,13 @@ var createChangeStreamCursor = function(self) {
|
|
|
258
377
|
* @event ChangeStream#end
|
|
259
378
|
* @type {null}
|
|
260
379
|
*/
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Emitted each time the change stream stores a new resume token.
|
|
383
|
+
*
|
|
384
|
+
* @event ChangeStream#resumeTokenChanged
|
|
385
|
+
* @type {ResumeToken}
|
|
386
|
+
*/
|
|
264
387
|
|
|
265
388
|
/**
|
|
266
389
|
* Fired when the stream encounters an error.
|
|
@@ -282,45 +405,26 @@ var createChangeStreamCursor = function(self) {
|
|
|
282
405
|
return changeStreamCursor;
|
|
283
406
|
};
|
|
284
407
|
|
|
285
|
-
function
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
return (
|
|
292
|
-
isMaster.maxWireVersion && isMaster.maxWireVersion >= 7 && self.options.startAtOperationTime
|
|
293
|
-
);
|
|
408
|
+
function applyKnownOptions(target, source, optionNames) {
|
|
409
|
+
optionNames.forEach(name => {
|
|
410
|
+
if (source[name]) {
|
|
411
|
+
target[name] = source[name];
|
|
412
|
+
}
|
|
413
|
+
});
|
|
294
414
|
}
|
|
295
415
|
|
|
296
|
-
var buildChangeStreamAggregationCommand = function(self) {
|
|
416
|
+
var buildChangeStreamAggregationCommand = function(self, options) {
|
|
417
|
+
options = options || {};
|
|
297
418
|
const topology = self.topology;
|
|
298
419
|
const namespace = self.namespace;
|
|
299
420
|
const pipeline = self.pipeline;
|
|
300
|
-
const options = self.options;
|
|
301
|
-
const cursorNamespace = self.cursorNamespace;
|
|
302
421
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
const resumeToken = getResumeToken(self);
|
|
308
|
-
const startAtOperationTime = getStartAtOperationTime(self);
|
|
309
|
-
if (resumeToken) {
|
|
310
|
-
changeStreamStageOptions.resumeAfter = resumeToken;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (startAtOperationTime) {
|
|
314
|
-
changeStreamStageOptions.startAtOperationTime = startAtOperationTime;
|
|
315
|
-
}
|
|
422
|
+
const changeStreamStageOptions = { fullDocument: options.fullDocument || 'default' };
|
|
423
|
+
applyKnownOptions(changeStreamStageOptions, options, CHANGE_STREAM_OPTIONS);
|
|
316
424
|
|
|
317
425
|
// Map cursor options
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (options[optionName]) {
|
|
321
|
-
cursorOptions[optionName] = options[optionName];
|
|
322
|
-
}
|
|
323
|
-
});
|
|
426
|
+
const cursorOptions = { cursorFactory: ChangeStreamCursor };
|
|
427
|
+
applyKnownOptions(cursorOptions, options, CURSOR_OPTIONS);
|
|
324
428
|
|
|
325
429
|
if (self.type === CHANGE_DOMAIN_TYPES.CLUSTER) {
|
|
326
430
|
changeStreamStageOptions.allChangesForCluster = true;
|
|
@@ -333,14 +437,15 @@ var buildChangeStreamAggregationCommand = function(self) {
|
|
|
333
437
|
var command = {
|
|
334
438
|
aggregate: self.type === CHANGE_DOMAIN_TYPES.COLLECTION ? namespace.collection : 1,
|
|
335
439
|
pipeline: changeStreamPipeline,
|
|
336
|
-
readConcern:
|
|
440
|
+
readConcern: new ReadConcern(ReadConcern.MAJORITY),
|
|
337
441
|
cursor: {
|
|
338
442
|
batchSize: options.batchSize || 1
|
|
339
443
|
}
|
|
340
444
|
};
|
|
341
445
|
|
|
342
446
|
// Create and return the cursor
|
|
343
|
-
|
|
447
|
+
// TODO: switch to passing namespace object later
|
|
448
|
+
return topology.cursor(namespace.toString(), command, cursorOptions);
|
|
344
449
|
};
|
|
345
450
|
|
|
346
451
|
// This method performs a basic server selection loop, satisfying the requirements of
|
|
@@ -382,6 +487,7 @@ function processNewChange(args) {
|
|
|
382
487
|
: changeStream.promiseLibrary.reject(error);
|
|
383
488
|
}
|
|
384
489
|
|
|
490
|
+
const cursor = changeStream.cursor;
|
|
385
491
|
const topology = changeStream.topology;
|
|
386
492
|
const options = changeStream.cursor.options;
|
|
387
493
|
|
|
@@ -389,11 +495,6 @@ function processNewChange(args) {
|
|
|
389
495
|
if (isResumableError(error) && !changeStream.attemptingResume) {
|
|
390
496
|
changeStream.attemptingResume = true;
|
|
391
497
|
|
|
392
|
-
if (!(getResumeToken(changeStream) || getStartAtOperationTime(changeStream))) {
|
|
393
|
-
const startAtOperationTime = changeStream.cursor.cursorState.operationTime;
|
|
394
|
-
changeStream.options = Object.assign({ startAtOperationTime }, changeStream.options);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
498
|
// stop listening to all events from old cursor
|
|
398
499
|
['data', 'close', 'end', 'error'].forEach(event =>
|
|
399
500
|
changeStream.cursor.removeAllListeners(event)
|
|
@@ -406,7 +507,7 @@ function processNewChange(args) {
|
|
|
406
507
|
if (eventEmitter) {
|
|
407
508
|
waitForTopologyConnected(topology, { readPreference: options.readPreference }, err => {
|
|
408
509
|
if (err) return changeStream.emit('error', err);
|
|
409
|
-
changeStream.cursor = createChangeStreamCursor(changeStream);
|
|
510
|
+
changeStream.cursor = createChangeStreamCursor(changeStream, cursor.resumeOptions);
|
|
410
511
|
});
|
|
411
512
|
|
|
412
513
|
return;
|
|
@@ -416,7 +517,7 @@ function processNewChange(args) {
|
|
|
416
517
|
waitForTopologyConnected(topology, { readPreference: options.readPreference }, err => {
|
|
417
518
|
if (err) return callback(err, null);
|
|
418
519
|
|
|
419
|
-
changeStream.cursor = createChangeStreamCursor(changeStream);
|
|
520
|
+
changeStream.cursor = createChangeStreamCursor(changeStream, cursor.resumeOptions);
|
|
420
521
|
changeStream.next(callback);
|
|
421
522
|
});
|
|
422
523
|
|
|
@@ -429,7 +530,9 @@ function processNewChange(args) {
|
|
|
429
530
|
resolve();
|
|
430
531
|
});
|
|
431
532
|
})
|
|
432
|
-
.then(
|
|
533
|
+
.then(
|
|
534
|
+
() => (changeStream.cursor = createChangeStreamCursor(changeStream, cursor.resumeOptions))
|
|
535
|
+
)
|
|
433
536
|
.then(() => changeStream.next());
|
|
434
537
|
}
|
|
435
538
|
|
|
@@ -440,9 +543,8 @@ function processNewChange(args) {
|
|
|
440
543
|
|
|
441
544
|
changeStream.attemptingResume = false;
|
|
442
545
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
var noResumeTokenError = new Error(
|
|
546
|
+
if (change && !change._id) {
|
|
547
|
+
const noResumeTokenError = new Error(
|
|
446
548
|
'A change stream document has been received that lacks a resume token (_id).'
|
|
447
549
|
);
|
|
448
550
|
|
|
@@ -451,7 +553,12 @@ function processNewChange(args) {
|
|
|
451
553
|
return changeStream.promiseLibrary.reject(noResumeTokenError);
|
|
452
554
|
}
|
|
453
555
|
|
|
454
|
-
|
|
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
|
+
}
|
|
455
562
|
|
|
456
563
|
// Return the change
|
|
457
564
|
if (eventEmitter) return changeStream.emit('change', change);
|