mongodb 3.3.0-beta1 → 3.3.2
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 +117 -0
- package/index.js +1 -0
- package/lib/admin.js +6 -6
- package/lib/aggregation_cursor.js +180 -226
- package/lib/change_stream.js +233 -121
- package/lib/collection.js +74 -39
- package/lib/command_cursor.js +87 -165
- package/lib/core/connection/connect.js +1 -1
- package/lib/core/connection/msg.js +2 -1
- package/lib/core/connection/pool.js +66 -41
- package/lib/core/cursor.js +605 -461
- package/lib/core/error.js +70 -1
- package/lib/core/index.js +1 -1
- package/lib/core/sdam/server.js +109 -10
- package/lib/core/sdam/server_description.js +14 -0
- package/lib/core/sdam/topology.js +34 -14
- package/lib/core/sdam/topology_description.js +6 -14
- package/lib/core/sessions.js +68 -12
- package/lib/core/topologies/mongos.js +10 -3
- package/lib/core/topologies/replset.js +49 -11
- package/lib/core/topologies/server.js +38 -3
- package/lib/core/topologies/shared.js +22 -0
- package/lib/core/transactions.js +1 -0
- package/lib/core/utils.js +45 -1
- package/lib/core/wireprotocol/command.js +2 -2
- package/lib/core/wireprotocol/get_more.js +4 -0
- package/lib/core/wireprotocol/query.js +8 -1
- package/lib/cursor.js +780 -840
- package/lib/db.js +31 -73
- package/lib/error.js +10 -8
- package/lib/gridfs-stream/download.js +12 -5
- package/lib/mongo_client.js +33 -21
- package/lib/operations/aggregate.js +77 -95
- package/lib/operations/close.js +46 -0
- package/lib/operations/collection_ops.js +7 -916
- package/lib/operations/command.js +2 -1
- package/lib/operations/command_v2.js +109 -0
- package/lib/operations/common_functions.js +48 -14
- package/lib/operations/connect.js +73 -9
- package/lib/operations/count.js +8 -8
- package/lib/operations/count_documents.js +24 -29
- package/lib/operations/create_collection.js +1 -0
- package/lib/operations/cursor_ops.js +22 -32
- package/lib/operations/db_ops.js +0 -178
- package/lib/operations/distinct.js +20 -21
- package/lib/operations/drop.js +1 -0
- package/lib/operations/estimated_document_count.js +43 -18
- package/lib/operations/execute_operation.js +115 -3
- package/lib/operations/explain.js +2 -6
- package/lib/operations/find.js +35 -0
- package/lib/operations/insert_one.js +1 -37
- package/lib/operations/list_collections.js +106 -0
- package/lib/operations/list_databases.js +38 -0
- package/lib/operations/list_indexes.js +28 -52
- package/lib/operations/operation.js +7 -1
- package/lib/operations/rename.js +1 -1
- package/lib/operations/to_array.js +3 -5
- package/lib/read_concern.js +7 -1
- package/lib/topologies/mongos.js +1 -1
- package/lib/topologies/replset.js +1 -1
- package/lib/topologies/server.js +2 -2
- package/lib/topologies/topology_base.js +4 -5
- package/lib/utils.js +4 -4
- package/package.json +1 -1
- package/lib/operations/aggregate_operation.js +0 -127
- package/lib/operations/mongo_client_ops.js +0 -731
package/lib/db.js
CHANGED
|
@@ -22,16 +22,16 @@ const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
|
|
22
22
|
const CONSTANTS = require('./constants');
|
|
23
23
|
const WriteConcern = require('./write_concern');
|
|
24
24
|
const ReadConcern = require('./read_concern');
|
|
25
|
+
const AggregationCursor = require('./aggregation_cursor');
|
|
25
26
|
|
|
26
27
|
// Operations
|
|
27
|
-
const aggregate = require('./operations/aggregate').aggregate;
|
|
28
28
|
const createListener = require('./operations/db_ops').createListener;
|
|
29
29
|
const ensureIndex = require('./operations/db_ops').ensureIndex;
|
|
30
30
|
const evaluate = require('./operations/db_ops').evaluate;
|
|
31
|
-
const listCollectionsTransforms = require('./operations/db_ops').listCollectionsTransforms;
|
|
32
31
|
const profilingInfo = require('./operations/db_ops').profilingInfo;
|
|
33
32
|
const validateDatabaseName = require('./operations/db_ops').validateDatabaseName;
|
|
34
33
|
|
|
34
|
+
const AggregateOperation = require('./operations/aggregate');
|
|
35
35
|
const AddUserOperation = require('./operations/add_user');
|
|
36
36
|
const CollectionsOperation = require('./operations/collections');
|
|
37
37
|
const CommandOperation = require('./operations/command');
|
|
@@ -41,6 +41,7 @@ const DropCollectionOperation = require('./operations/drop').DropCollectionOpera
|
|
|
41
41
|
const DropDatabaseOperation = require('./operations/drop').DropDatabaseOperation;
|
|
42
42
|
const ExecuteDbAdminCommandOperation = require('./operations/execute_db_admin_command');
|
|
43
43
|
const IndexInformationOperation = require('./operations/index_information');
|
|
44
|
+
const ListCollectionsOperation = require('./operations/list_collections');
|
|
44
45
|
const ProfilingLevelOperation = require('./operations/profiling_level');
|
|
45
46
|
const RemoveUserOperation = require('./operations/remove_user');
|
|
46
47
|
const RenameOperation = require('./operations/rename');
|
|
@@ -329,7 +330,19 @@ Db.prototype.aggregate = function(pipeline, options, callback) {
|
|
|
329
330
|
options = {};
|
|
330
331
|
}
|
|
331
332
|
|
|
332
|
-
|
|
333
|
+
const cursor = new AggregationCursor(
|
|
334
|
+
this.s.topology,
|
|
335
|
+
new AggregateOperation(this, pipeline, options),
|
|
336
|
+
options
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
// TODO: remove this when NODE-2074 is resolved
|
|
340
|
+
if (typeof callback === 'function') {
|
|
341
|
+
callback(null, cursor);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return cursor;
|
|
333
346
|
};
|
|
334
347
|
|
|
335
348
|
/**
|
|
@@ -489,7 +502,7 @@ Db.prototype.collection = function(name, options, callback) {
|
|
|
489
502
|
* @param {string} [options.validationAction] Determines whether to error on invalid documents or just warn about the violations but allow invalid documents to be inserted on MongoDB 3.2 or higher.
|
|
490
503
|
* @param {object} [options.indexOptionDefaults] Allows users to specify a default configuration for indexes when creating a collection on MongoDB 3.2 or higher.
|
|
491
504
|
* @param {string} [options.viewOn] The name of the source collection or view from which to create the view. The name is not the full namespace of the collection or view; i.e. does not include the database name and implies the same database as the view to create on MongoDB 3.4 or higher.
|
|
492
|
-
* @param {array} [options.pipeline] An array that consists of the aggregation pipeline stage.
|
|
505
|
+
* @param {array} [options.pipeline] An array that consists of the aggregation pipeline stage. Creates the view by applying the specified pipeline to the viewOn collection or view on MongoDB 3.4 or higher.
|
|
493
506
|
* @param {object} [options.collation] Specify collation (MongoDB 3.4 or higher) settings for update operation (see 3.4 documentation for available fields).
|
|
494
507
|
* @param {ClientSession} [options.session] optional session to use for this operation
|
|
495
508
|
* @param {Db~collectionResultCallback} [callback] The results callback
|
|
@@ -505,7 +518,9 @@ Db.prototype.createCollection = deprecateOptions(
|
|
|
505
518
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
506
519
|
options = options || {};
|
|
507
520
|
options.promiseLibrary = options.promiseLibrary || this.s.promiseLibrary;
|
|
508
|
-
|
|
521
|
+
options.readConcern = options.readConcern
|
|
522
|
+
? new ReadConcern(options.readConcern.level)
|
|
523
|
+
: this.readConcern;
|
|
509
524
|
const createCollectionOperation = new CreateCollectionOperation(this, name, options);
|
|
510
525
|
|
|
511
526
|
return executeOperation(this.s.topology, createCollectionOperation, callback);
|
|
@@ -557,72 +572,11 @@ Db.prototype.listCollections = function(filter, options) {
|
|
|
557
572
|
filter = filter || {};
|
|
558
573
|
options = options || {};
|
|
559
574
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
// Ensure valid readPreference
|
|
566
|
-
options.readPreference = resolveReadPreference(this, options);
|
|
567
|
-
|
|
568
|
-
// Cursor options
|
|
569
|
-
let cursor = options.batchSize ? { batchSize: options.batchSize } : {};
|
|
570
|
-
|
|
571
|
-
// We have a list collections command
|
|
572
|
-
if (this.serverConfig.capabilities().hasListCollectionsCommand) {
|
|
573
|
-
const nameOnly = typeof options.nameOnly === 'boolean' ? options.nameOnly : false;
|
|
574
|
-
// Build the command
|
|
575
|
-
const command = { listCollections: true, filter, cursor, nameOnly };
|
|
576
|
-
// Set the AggregationCursor constructor
|
|
577
|
-
options.cursorFactory = CommandCursor;
|
|
578
|
-
// Create the cursor
|
|
579
|
-
cursor = this.s.topology.cursor(
|
|
580
|
-
this.s.namespace.withCollection('$cmd').toString(),
|
|
581
|
-
command,
|
|
582
|
-
options
|
|
583
|
-
);
|
|
584
|
-
// Do we have a readPreference, apply it
|
|
585
|
-
if (options.readPreference) {
|
|
586
|
-
cursor.setReadPreference(options.readPreference);
|
|
587
|
-
}
|
|
588
|
-
// Return the cursor
|
|
589
|
-
return cursor;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
// We cannot use the listCollectionsCommand
|
|
593
|
-
if (!this.serverConfig.capabilities().hasListCollectionsCommand) {
|
|
594
|
-
// If we have legacy mode and have not provided a full db name filter it
|
|
595
|
-
if (
|
|
596
|
-
typeof filter.name === 'string' &&
|
|
597
|
-
!new RegExp('^' + this.databaseName + '\\.').test(filter.name)
|
|
598
|
-
) {
|
|
599
|
-
filter = Object.assign({}, filter);
|
|
600
|
-
filter.name = this.s.namespace.withCollection(filter.name).toString();
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
// No filter, filter by current database
|
|
605
|
-
if (filter == null) {
|
|
606
|
-
filter.name = `/${this.databaseName}/`;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
// Rewrite the filter to use $and to filter out indexes
|
|
610
|
-
if (filter.name) {
|
|
611
|
-
filter = { $and: [{ name: filter.name }, { name: /^((?!\$).)*$/ }] };
|
|
612
|
-
} else {
|
|
613
|
-
filter = { name: /^((?!\$).)*$/ };
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// Return options
|
|
617
|
-
const _options = { transforms: listCollectionsTransforms(this.databaseName) };
|
|
618
|
-
// Get the cursor
|
|
619
|
-
cursor = this.collection(CONSTANTS.SYSTEM_NAMESPACE_COLLECTION).find(filter, _options);
|
|
620
|
-
// Do we have a readPreference, apply it
|
|
621
|
-
if (options.readPreference) cursor.setReadPreference(options.readPreference);
|
|
622
|
-
// Set the passed in batch size if one was provided
|
|
623
|
-
if (options.batchSize) cursor = cursor.batchSize(options.batchSize);
|
|
624
|
-
// We have a fallback mode using legacy systems collections
|
|
625
|
-
return cursor;
|
|
575
|
+
return new CommandCursor(
|
|
576
|
+
this.s.topology,
|
|
577
|
+
new ListCollectionsOperation(this, filter, options),
|
|
578
|
+
options
|
|
579
|
+
);
|
|
626
580
|
};
|
|
627
581
|
|
|
628
582
|
/**
|
|
@@ -687,6 +641,10 @@ Db.prototype.renameCollection = function(fromCollection, toCollection, options,
|
|
|
687
641
|
* @method
|
|
688
642
|
* @param {string} name Name of collection to drop
|
|
689
643
|
* @param {Object} [options] Optional settings
|
|
644
|
+
* @param {WriteConcern} [options.writeConcern] A full WriteConcern object
|
|
645
|
+
* @param {(number|string)} [options.w] The write concern
|
|
646
|
+
* @param {number} [options.wtimeout] The write concern timeout
|
|
647
|
+
* @param {boolean} [options.j] The journal write concern
|
|
690
648
|
* @param {ClientSession} [options.session] optional session to use for this operation
|
|
691
649
|
* @param {Db~resultCallback} [callback] The results callback
|
|
692
650
|
* @return {Promise} returns Promise if no callback passed
|
|
@@ -777,7 +735,7 @@ Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
|
|
|
777
735
|
* @param {number} [options.max] For geospatial indexes set the high bound for the co-ordinates.
|
|
778
736
|
* @param {number} [options.v] Specify the format version of the indexes.
|
|
779
737
|
* @param {number} [options.expireAfterSeconds] Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher)
|
|
780
|
-
* @param {
|
|
738
|
+
* @param {string} [options.name] Override the autogenerated index name (useful if the resulting name is larger than 128 bytes)
|
|
781
739
|
* @param {object} [options.partialFilterExpression] Creates a partial index based on the given filter object (MongoDB 3.2 or higher)
|
|
782
740
|
* @param {ClientSession} [options.session] optional session to use for this operation
|
|
783
741
|
* @param {Db~resultCallback} [callback] The command result callback
|
|
@@ -975,7 +933,7 @@ Db.prototype.unref = function() {
|
|
|
975
933
|
* @param {number} [options.batchSize] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
976
934
|
* @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
977
935
|
* @param {ReadPreference} [options.readPreference] The read preference. Defaults to the read preference of the database. See {@link https://docs.mongodb.com/manual/reference/read-preference|read preference documentation}.
|
|
978
|
-
* @param {Timestamp} [options.
|
|
936
|
+
* @param {Timestamp} [options.startAtOperationTime] receive change events that occur after the specified timestamp
|
|
979
937
|
* @param {ClientSession} [options.session] optional session to use for this operation
|
|
980
938
|
* @return {ChangeStream} a ChangeStream instance.
|
|
981
939
|
*/
|
package/lib/error.js
CHANGED
|
@@ -9,15 +9,15 @@ const GET_MORE_NON_RESUMABLE_CODES = new Set([
|
|
|
9
9
|
11601 // Interrupted
|
|
10
10
|
]);
|
|
11
11
|
|
|
12
|
-
// From spec@https://github.com/mongodb/specifications/blob/
|
|
12
|
+
// From spec@https://github.com/mongodb/specifications/blob/7a2e93d85935ee4b1046a8d2ad3514c657dc74fa/source/change-streams/change-streams.rst#resumable-error:
|
|
13
13
|
//
|
|
14
14
|
// An error is considered resumable if it meets any of the following criteria:
|
|
15
15
|
// - any error encountered which is not a server error (e.g. a timeout error or network error)
|
|
16
|
-
// - any server error response from a getMore command excluding those containing the
|
|
16
|
+
// - any server error response from a getMore command excluding those containing the error label
|
|
17
|
+
// NonRetryableChangeStreamError and those containing the following error codes:
|
|
17
18
|
// - Interrupted: 11601
|
|
18
19
|
// - CappedPositionLost: 136
|
|
19
20
|
// - CursorKilled: 237
|
|
20
|
-
// - a server error response with an error message containing the substring "not master" or "node is recovering"
|
|
21
21
|
//
|
|
22
22
|
// An error on an aggregate command is not a resumable error. Only errors on a getMore command may be considered resumable errors.
|
|
23
23
|
|
|
@@ -32,11 +32,13 @@ function isResumableError(error) {
|
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
if (error instanceof MongoNetworkError) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return !(
|
|
40
|
+
GET_MORE_NON_RESUMABLE_CODES.has(error.code) ||
|
|
41
|
+
error.hasErrorLabel('NonRetryableChangeStreamError')
|
|
40
42
|
);
|
|
41
43
|
}
|
|
42
44
|
|
|
@@ -185,12 +185,19 @@ function doRead(_this) {
|
|
|
185
185
|
}
|
|
186
186
|
if (!doc) {
|
|
187
187
|
_this.push(null);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
|
|
189
|
+
process.nextTick(() => {
|
|
190
|
+
_this.s.cursor.close(function(error) {
|
|
191
|
+
if (error) {
|
|
192
|
+
__handleError(_this, error);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
_this.emit('close');
|
|
197
|
+
});
|
|
193
198
|
});
|
|
199
|
+
|
|
200
|
+
return;
|
|
194
201
|
}
|
|
195
202
|
|
|
196
203
|
var bytesRemaining = _this.s.file.length - _this.s.bytesRead;
|
package/lib/mongo_client.js
CHANGED
|
@@ -3,16 +3,17 @@
|
|
|
3
3
|
const ChangeStream = require('./change_stream');
|
|
4
4
|
const Db = require('./db');
|
|
5
5
|
const EventEmitter = require('events').EventEmitter;
|
|
6
|
-
const
|
|
6
|
+
const executeOperation = require('./operations/execute_operation');
|
|
7
7
|
const inherits = require('util').inherits;
|
|
8
8
|
const MongoError = require('./core').MongoError;
|
|
9
9
|
const deprecate = require('util').deprecate;
|
|
10
10
|
const WriteConcern = require('./write_concern');
|
|
11
|
+
const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
|
12
|
+
const ReadPreference = require('./core/topologies/read_preference');
|
|
11
13
|
|
|
12
14
|
// Operations
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const closeOperation = require('./operations/mongo_client_ops').closeOperation;
|
|
15
|
+
const ConnectOperation = require('./operations/connect');
|
|
16
|
+
const CloseOperation = require('./operations/close');
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* @fileOverview The **MongoClient** class is a class that allows for making Connections to MongoDB.
|
|
@@ -54,7 +55,9 @@ const closeOperation = require('./operations/mongo_client_ops').closeOperation;
|
|
|
54
55
|
*/
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
|
-
* Configuration options for a automatic client encryption
|
|
58
|
+
* Configuration options for a automatic client encryption.
|
|
59
|
+
*
|
|
60
|
+
* **NOTE**: Support for client side encryption is in beta. Backwards-breaking changes may be made before the final release.
|
|
58
61
|
*
|
|
59
62
|
* @typedef {Object} AutoEncryptionOptions
|
|
60
63
|
* @property {MongoClient} [keyVaultClient] A `MongoClient` used to fetch keys from a key vault
|
|
@@ -67,6 +70,11 @@ const closeOperation = require('./operations/mongo_client_ops').closeOperation;
|
|
|
67
70
|
* @property {string} [kmsProviders.local.key] The master key used to encrypt/decrypt data keys
|
|
68
71
|
* @property {object} [schemaMap] A map of namespaces to a local JSON schema for encryption
|
|
69
72
|
* @property {boolean} [bypassAutoEncryption] Allows the user to bypass auto encryption, maintaining implicit decryption
|
|
73
|
+
* @property {object} [extraOptions] Extra options related to the mongocryptd process
|
|
74
|
+
* @property {string} [extraOptions.mongocryptURI] A local process the driver communicates with to determine how to encrypt values in a command. Defaults to "mongodb://%2Fvar%2Fmongocryptd.sock" if domain sockets are available or "mongodb://localhost:27020" otherwise
|
|
75
|
+
* @property {boolean} [extraOptions.mongocryptdBypassSpawn=false] If true, autoEncryption will not attempt to spawn a mongocryptd before connecting
|
|
76
|
+
* @property {string} [extraOptions.mongocryptdSpawnPath] The path to the mongocryptd executable on the system
|
|
77
|
+
* @property {string[]} [extraOptions.mongocryptdSpawnArgs] Command line arguments to use when auto-spawning a mongocryptd
|
|
70
78
|
*/
|
|
71
79
|
|
|
72
80
|
/**
|
|
@@ -148,9 +156,10 @@ function MongoClient(url, options) {
|
|
|
148
156
|
url: url,
|
|
149
157
|
options: options || {},
|
|
150
158
|
promiseLibrary: null,
|
|
151
|
-
dbCache:
|
|
152
|
-
sessions:
|
|
153
|
-
writeConcern: WriteConcern.fromOptions(options)
|
|
159
|
+
dbCache: new Map(),
|
|
160
|
+
sessions: new Set(),
|
|
161
|
+
writeConcern: WriteConcern.fromOptions(options),
|
|
162
|
+
namespace: new MongoDBNamespace('admin')
|
|
154
163
|
};
|
|
155
164
|
|
|
156
165
|
// Get the promiseLibrary
|
|
@@ -172,6 +181,13 @@ Object.defineProperty(MongoClient.prototype, 'writeConcern', {
|
|
|
172
181
|
}
|
|
173
182
|
});
|
|
174
183
|
|
|
184
|
+
Object.defineProperty(MongoClient.prototype, 'readPreference', {
|
|
185
|
+
enumerable: true,
|
|
186
|
+
get: function() {
|
|
187
|
+
return ReadPreference.primary;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
175
191
|
/**
|
|
176
192
|
* The callback format for results
|
|
177
193
|
* @callback MongoClient~connectCallback
|
|
@@ -191,16 +207,13 @@ Object.defineProperty(MongoClient.prototype, 'writeConcern', {
|
|
|
191
207
|
* @return {Promise<MongoClient>} returns Promise if no callback passed
|
|
192
208
|
*/
|
|
193
209
|
MongoClient.prototype.connect = function(callback) {
|
|
194
|
-
// Validate options object
|
|
195
|
-
const err = validOptions(this.s.options);
|
|
196
|
-
|
|
197
210
|
if (typeof callback === 'string') {
|
|
198
211
|
throw new TypeError('`connect` only accepts a callback');
|
|
199
212
|
}
|
|
200
213
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
214
|
+
const operation = new ConnectOperation(this);
|
|
215
|
+
|
|
216
|
+
return executeOperation(this, operation, callback);
|
|
204
217
|
};
|
|
205
218
|
|
|
206
219
|
MongoClient.prototype.logout = deprecate(function(options, callback) {
|
|
@@ -217,9 +230,8 @@ MongoClient.prototype.logout = deprecate(function(options, callback) {
|
|
|
217
230
|
*/
|
|
218
231
|
MongoClient.prototype.close = function(force, callback) {
|
|
219
232
|
if (typeof force === 'function') (callback = force), (force = false);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
});
|
|
233
|
+
const operation = new CloseOperation(this, force);
|
|
234
|
+
return executeOperation(this, operation, callback);
|
|
223
235
|
};
|
|
224
236
|
|
|
225
237
|
/**
|
|
@@ -247,8 +259,8 @@ MongoClient.prototype.db = function(dbName, options) {
|
|
|
247
259
|
const finalOptions = Object.assign({}, this.s.options, options);
|
|
248
260
|
|
|
249
261
|
// Do we have the db in the cache already
|
|
250
|
-
if (this.s.dbCache
|
|
251
|
-
return this.s.dbCache
|
|
262
|
+
if (this.s.dbCache.has(dbName) && finalOptions.returnNonCachedInstance !== true) {
|
|
263
|
+
return this.s.dbCache.get(dbName);
|
|
252
264
|
}
|
|
253
265
|
|
|
254
266
|
// Add promiseLibrary
|
|
@@ -263,7 +275,7 @@ MongoClient.prototype.db = function(dbName, options) {
|
|
|
263
275
|
const db = new Db(dbName, this.topology, finalOptions);
|
|
264
276
|
|
|
265
277
|
// Add the db to the cache
|
|
266
|
-
this.s.dbCache
|
|
278
|
+
this.s.dbCache.set(dbName, db);
|
|
267
279
|
// Return the database
|
|
268
280
|
return db;
|
|
269
281
|
};
|
|
@@ -437,7 +449,7 @@ MongoClient.prototype.withSession = function(options, operation) {
|
|
|
437
449
|
* @param {number} [options.batchSize] The number of documents to return per batch. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
438
450
|
* @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
439
451
|
* @param {ReadPreference} [options.readPreference] The read preference. See {@link https://docs.mongodb.com/manual/reference/read-preference|read preference documentation}.
|
|
440
|
-
* @param {Timestamp} [options.
|
|
452
|
+
* @param {Timestamp} [options.startAtOperationTime] receive change events that occur after the specified timestamp
|
|
441
453
|
* @param {ClientSession} [options.session] optional session to use for this operation
|
|
442
454
|
* @return {ChangeStream} a ChangeStream instance.
|
|
443
455
|
*/
|
|
@@ -1,124 +1,106 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const applyWriteConcern = require('../utils').applyWriteConcern;
|
|
5
|
-
const decorateWithCollation = require('../utils').decorateWithCollation;
|
|
6
|
-
const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
|
7
|
-
const handleCallback = require('../utils').handleCallback;
|
|
3
|
+
const CommandOperationV2 = require('./command_v2');
|
|
8
4
|
const MongoError = require('../core').MongoError;
|
|
9
|
-
const
|
|
10
|
-
const
|
|
5
|
+
const maxWireVersion = require('../core/utils').maxWireVersion;
|
|
6
|
+
const ReadPreference = require('../core').ReadPreference;
|
|
7
|
+
const Aspect = require('./operation').Aspect;
|
|
8
|
+
const defineAspects = require('./operation').defineAspects;
|
|
11
9
|
|
|
12
10
|
const DB_AGGREGATE_COLLECTION = 1;
|
|
13
|
-
|
|
14
11
|
const MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT = 8;
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
let command;
|
|
40
|
-
let namespace;
|
|
41
|
-
let optionSources;
|
|
42
|
-
|
|
43
|
-
if (isDbAggregate) {
|
|
44
|
-
command = { aggregate: DB_AGGREGATE_COLLECTION, pipeline: pipeline };
|
|
45
|
-
namespace = db.s.namespace.withCollection(DB_AGGREGATE_COLLECTION);
|
|
46
|
-
|
|
47
|
-
optionSources = { db };
|
|
48
|
-
} else {
|
|
49
|
-
command = { aggregate: coll.collectionName, pipeline: pipeline };
|
|
50
|
-
namespace = coll.s.namespace;
|
|
51
|
-
|
|
52
|
-
optionSources = { db: coll.s.db, collection: coll };
|
|
53
|
-
}
|
|
13
|
+
class AggregateOperation extends CommandOperationV2 {
|
|
14
|
+
constructor(parent, pipeline, options) {
|
|
15
|
+
super(parent, options, { fullResponse: true });
|
|
16
|
+
|
|
17
|
+
this.target =
|
|
18
|
+
parent.s.namespace && parent.s.namespace.collection
|
|
19
|
+
? parent.s.namespace.collection
|
|
20
|
+
: DB_AGGREGATE_COLLECTION;
|
|
21
|
+
|
|
22
|
+
this.pipeline = pipeline;
|
|
23
|
+
|
|
24
|
+
// determine if we have a write stage, override read preference if so
|
|
25
|
+
this.hasWriteStage = false;
|
|
26
|
+
if (typeof options.out === 'string') {
|
|
27
|
+
this.pipeline = this.pipeline.concat({ $out: options.out });
|
|
28
|
+
this.hasWriteStage = true;
|
|
29
|
+
} else if (pipeline.length > 0) {
|
|
30
|
+
const finalStage = pipeline[pipeline.length - 1];
|
|
31
|
+
if (finalStage.$out || finalStage.$merge) {
|
|
32
|
+
this.hasWriteStage = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
54
35
|
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
if (this.hasWriteStage) {
|
|
37
|
+
this.readPreference = ReadPreference.primary;
|
|
38
|
+
}
|
|
57
39
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
40
|
+
if (options.explain && (this.readConcern || this.writeConcern)) {
|
|
41
|
+
throw new MongoError(
|
|
42
|
+
'"explain" cannot be used on an aggregate call with readConcern/writeConcern'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
61
45
|
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
if (options.cursor != null && typeof options.cursor !== 'object') {
|
|
47
|
+
throw new MongoError('cursor options must be an object');
|
|
48
|
+
}
|
|
64
49
|
}
|
|
65
50
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
} catch (err) {
|
|
69
|
-
if (typeof callback === 'function') return callback(err, null);
|
|
70
|
-
throw err;
|
|
51
|
+
get canRetryRead() {
|
|
52
|
+
return !this.hasWriteStage;
|
|
71
53
|
}
|
|
72
54
|
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
addToPipeline(stage) {
|
|
56
|
+
this.pipeline.push(stage);
|
|
75
57
|
}
|
|
76
58
|
|
|
77
|
-
|
|
78
|
-
|
|
59
|
+
execute(server, callback) {
|
|
60
|
+
const options = this.options;
|
|
61
|
+
const serverWireVersion = maxWireVersion(server);
|
|
62
|
+
const command = { aggregate: this.target, pipeline: this.pipeline };
|
|
79
63
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
options = Object.assign({}, options);
|
|
83
|
-
|
|
84
|
-
// Ensure we have the right read preference inheritance
|
|
85
|
-
options.readPreference = resolveReadPreference(isDbAggregate ? db : coll, options);
|
|
86
|
-
|
|
87
|
-
if (options.explain) {
|
|
88
|
-
if (command.readConcern || command.writeConcern) {
|
|
89
|
-
throw toError('"explain" cannot be used on an aggregate call with readConcern/writeConcern');
|
|
64
|
+
if (this.hasWriteStage && serverWireVersion < MIN_WIRE_VERSION_$OUT_READ_CONCERN_SUPPORT) {
|
|
65
|
+
this.readConcern = null;
|
|
90
66
|
}
|
|
91
|
-
command.explain = options.explain;
|
|
92
|
-
}
|
|
93
67
|
|
|
94
|
-
|
|
68
|
+
if (serverWireVersion >= 5) {
|
|
69
|
+
if (this.hasWriteStage && this.writeConcern) {
|
|
70
|
+
Object.assign(command, { writeConcern: this.writeConcern });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
95
73
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
74
|
+
if (options.bypassDocumentValidation === true) {
|
|
75
|
+
command.bypassDocumentValidation = options.bypassDocumentValidation;
|
|
76
|
+
}
|
|
100
77
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
78
|
+
if (typeof options.allowDiskUse === 'boolean') {
|
|
79
|
+
command.allowDiskUse = options.allowDiskUse;
|
|
80
|
+
}
|
|
104
81
|
|
|
105
|
-
|
|
106
|
-
|
|
82
|
+
if (options.hint) {
|
|
83
|
+
command.hint = options.hint;
|
|
84
|
+
}
|
|
107
85
|
|
|
108
|
-
|
|
109
|
-
|
|
86
|
+
if (options.explain) {
|
|
87
|
+
options.full = false;
|
|
88
|
+
command.explain = options.explain;
|
|
89
|
+
}
|
|
110
90
|
|
|
111
|
-
|
|
112
|
-
if (!
|
|
113
|
-
|
|
91
|
+
command.cursor = options.cursor || {};
|
|
92
|
+
if (options.batchSize && !this.hasWriteStage) {
|
|
93
|
+
command.cursor.batchSize = options.batchSize;
|
|
114
94
|
}
|
|
115
95
|
|
|
116
|
-
|
|
96
|
+
super.executeCommand(server, command, callback);
|
|
117
97
|
}
|
|
118
|
-
|
|
119
|
-
return handleCallback(callback, null, topology.cursor(namespace.toString(), command, options));
|
|
120
98
|
}
|
|
121
99
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
100
|
+
defineAspects(AggregateOperation, [
|
|
101
|
+
Aspect.READ_OPERATION,
|
|
102
|
+
Aspect.RETRYABLE,
|
|
103
|
+
Aspect.EXECUTE_WITH_SELECTION
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
module.exports = AggregateOperation;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Aspect = require('./operation').Aspect;
|
|
4
|
+
const defineAspects = require('./operation').defineAspects;
|
|
5
|
+
const OperationBase = require('./operation').OperationBase;
|
|
6
|
+
|
|
7
|
+
class CloseOperation extends OperationBase {
|
|
8
|
+
constructor(client, force) {
|
|
9
|
+
super();
|
|
10
|
+
this.client = client;
|
|
11
|
+
this.force = force;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
execute(callback) {
|
|
15
|
+
const client = this.client;
|
|
16
|
+
const force = this.force;
|
|
17
|
+
const completeClose = err => {
|
|
18
|
+
client.emit('close', client);
|
|
19
|
+
for (const item of client.s.dbCache) {
|
|
20
|
+
item[1].emit('close', client);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
client.removeAllListeners('close');
|
|
24
|
+
callback(err, null);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (client.topology == null) {
|
|
28
|
+
completeClose();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
client.topology.close(force, err => {
|
|
33
|
+
const autoEncrypter = client.topology.s.options.autoEncrypter;
|
|
34
|
+
if (!autoEncrypter) {
|
|
35
|
+
completeClose(err);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
autoEncrypter.teardown(force, err2 => completeClose(err || err2));
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
defineAspects(CloseOperation, [Aspect.SKIP_SESSION]);
|
|
45
|
+
|
|
46
|
+
module.exports = CloseOperation;
|