mongodb 2.2.36 → 3.0.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/.eslintrc +24 -10
- package/CHANGES_3.0.0.md +288 -0
- package/HISTORY.md +120 -25
- package/README.md +247 -176
- package/conf.json +15 -14
- package/index.js +12 -6
- package/lib/admin.js +156 -364
- package/lib/aggregation_cursor.js +86 -88
- package/lib/apm.js +192 -149
- package/lib/authenticate.js +73 -53
- package/lib/bulk/common.js +140 -115
- package/lib/bulk/ordered.js +273 -195
- package/lib/bulk/unordered.js +291 -201
- package/lib/change_stream.js +359 -0
- package/lib/collection.js +1128 -1368
- package/lib/command_cursor.js +100 -73
- package/lib/cursor.js +454 -358
- package/lib/db.js +775 -771
- package/lib/gridfs/chunk.js +38 -34
- package/lib/gridfs/grid_store.js +590 -593
- package/lib/gridfs-stream/download.js +46 -40
- package/lib/gridfs-stream/index.js +24 -45
- package/lib/gridfs-stream/upload.js +28 -26
- package/lib/metadata.js +22 -16
- package/lib/mongo_client.js +708 -285
- package/lib/topologies/mongos.js +444 -0
- package/lib/topologies/replset.js +501 -0
- package/lib/topologies/server.js +448 -0
- package/lib/topologies/topology_base.js +441 -0
- package/lib/url_parser.js +334 -257
- package/lib/utils.js +210 -132
- package/package.json +20 -32
- package/yarn.lock +3728 -0
- package/lib/mongos.js +0 -533
- package/lib/read_preference.js +0 -131
- package/lib/replset.js +0 -582
- package/lib/server.js +0 -518
- package/lib/topology_base.js +0 -191
package/lib/mongo_client.js
CHANGED
|
@@ -1,64 +1,139 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var parse = require('./url_parser')
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var parse = require('./url_parser'),
|
|
4
|
+
Server = require('./topologies/server'),
|
|
5
|
+
Mongos = require('./topologies/mongos'),
|
|
6
|
+
ReplSet = require('./topologies/replset'),
|
|
7
|
+
EventEmitter = require('events').EventEmitter,
|
|
8
|
+
inherits = require('util').inherits,
|
|
9
|
+
Define = require('./metadata'),
|
|
10
|
+
ReadPreference = require('mongodb-core').ReadPreference,
|
|
11
|
+
Logger = require('mongodb-core').Logger,
|
|
12
|
+
MongoError = require('mongodb-core').MongoError,
|
|
13
|
+
handleCallback = require('./utils').handleCallback,
|
|
14
|
+
Db = require('./db'),
|
|
15
|
+
f = require('util').format,
|
|
16
|
+
shallowClone = require('./utils').shallowClone,
|
|
17
|
+
authenticate = require('./authenticate'),
|
|
18
|
+
ServerSessionPool = require('mongodb-core').Sessions.ServerSessionPool,
|
|
19
|
+
executeOperation = require('./utils').executeOperation;
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* @fileOverview The **MongoClient** class is a class that allows for making Connections to MongoDB.
|
|
21
23
|
*
|
|
22
24
|
* @example
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
+
* // Connect using a MongoClient instance
|
|
26
|
+
* const MongoClient = require('mongodb').MongoClient;
|
|
27
|
+
* const test = require('assert');
|
|
25
28
|
* // Connection url
|
|
26
|
-
*
|
|
29
|
+
* const url = 'mongodb://localhost:27017';
|
|
30
|
+
* // Database Name
|
|
31
|
+
* const dbName = 'test';
|
|
27
32
|
* // Connect using MongoClient
|
|
28
|
-
* MongoClient
|
|
29
|
-
*
|
|
30
|
-
* db.
|
|
33
|
+
* const mongoClient = new MongoClient(url);
|
|
34
|
+
* mongoClient.connect(function(err, client) {
|
|
35
|
+
* const db = client.db(dbName);
|
|
36
|
+
* client.close();
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* // Connect using the MongoClient.connect static method
|
|
41
|
+
* const MongoClient = require('mongodb').MongoClient;
|
|
42
|
+
* const test = require('assert');
|
|
43
|
+
* // Connection url
|
|
44
|
+
* const url = 'mongodb://localhost:27017';
|
|
45
|
+
* // Database Name
|
|
46
|
+
* const dbName = 'test';
|
|
47
|
+
* // Connect using MongoClient
|
|
48
|
+
* MongoClient.connect(url, function(err, client) {
|
|
49
|
+
* const db = client.db(dbName);
|
|
50
|
+
* client.close();
|
|
31
51
|
* });
|
|
32
52
|
*/
|
|
33
|
-
var validOptionNames = [
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
'
|
|
53
|
+
var validOptionNames = [
|
|
54
|
+
'poolSize',
|
|
55
|
+
'ssl',
|
|
56
|
+
'sslValidate',
|
|
57
|
+
'sslCA',
|
|
58
|
+
'sslCert',
|
|
59
|
+
'sslKey',
|
|
60
|
+
'sslPass',
|
|
61
|
+
'sslCRL',
|
|
62
|
+
'autoReconnect',
|
|
63
|
+
'noDelay',
|
|
64
|
+
'keepAlive',
|
|
65
|
+
'keepAliveInitialDelay',
|
|
66
|
+
'connectTimeoutMS',
|
|
67
|
+
'family',
|
|
68
|
+
'socketTimeoutMS',
|
|
69
|
+
'reconnectTries',
|
|
70
|
+
'reconnectInterval',
|
|
71
|
+
'ha',
|
|
72
|
+
'haInterval',
|
|
73
|
+
'replicaSet',
|
|
74
|
+
'secondaryAcceptableLatencyMS',
|
|
75
|
+
'acceptableLatencyMS',
|
|
76
|
+
'connectWithNoPrimary',
|
|
77
|
+
'authSource',
|
|
78
|
+
'w',
|
|
79
|
+
'wtimeout',
|
|
80
|
+
'j',
|
|
81
|
+
'forceServerObjectId',
|
|
82
|
+
'serializeFunctions',
|
|
83
|
+
'ignoreUndefined',
|
|
84
|
+
'raw',
|
|
85
|
+
'bufferMaxEntries',
|
|
86
|
+
'readPreference',
|
|
87
|
+
'pkFactory',
|
|
88
|
+
'promiseLibrary',
|
|
89
|
+
'readConcern',
|
|
90
|
+
'maxStalenessSeconds',
|
|
91
|
+
'loggerLevel',
|
|
92
|
+
'logger',
|
|
93
|
+
'promoteValues',
|
|
94
|
+
'promoteBuffers',
|
|
95
|
+
'promoteLongs',
|
|
96
|
+
'domainsEnabled',
|
|
97
|
+
'checkServerIdentity',
|
|
98
|
+
'validateOptions',
|
|
99
|
+
'appname',
|
|
100
|
+
'auth',
|
|
101
|
+
'user',
|
|
102
|
+
'password',
|
|
103
|
+
'authMechanism',
|
|
104
|
+
'compression',
|
|
105
|
+
'fsync',
|
|
106
|
+
'readPreferenceTags',
|
|
107
|
+
'numberOfRetries',
|
|
108
|
+
'auto_reconnect',
|
|
109
|
+
'minSize'
|
|
110
|
+
];
|
|
111
|
+
|
|
42
112
|
var ignoreOptionNames = ['native_parser'];
|
|
43
113
|
var legacyOptionNames = ['server', 'replset', 'replSet', 'mongos', 'db'];
|
|
44
114
|
|
|
45
115
|
function validOptions(options) {
|
|
46
116
|
var _validOptions = validOptionNames.concat(legacyOptionNames);
|
|
47
117
|
|
|
48
|
-
for(var name in options) {
|
|
49
|
-
if(ignoreOptionNames.indexOf(name)
|
|
118
|
+
for (var name in options) {
|
|
119
|
+
if (ignoreOptionNames.indexOf(name) !== -1) {
|
|
50
120
|
continue;
|
|
51
121
|
}
|
|
52
122
|
|
|
53
|
-
if(_validOptions.indexOf(name)
|
|
123
|
+
if (_validOptions.indexOf(name) === -1 && options.validateOptions) {
|
|
54
124
|
return new MongoError(f('option %s is not supported', name));
|
|
55
|
-
} else if(_validOptions.indexOf(name)
|
|
125
|
+
} else if (_validOptions.indexOf(name) === -1) {
|
|
56
126
|
console.warn(f('the options [%s] is not supported', name));
|
|
57
127
|
}
|
|
58
128
|
|
|
59
|
-
if(legacyOptionNames.indexOf(name)
|
|
60
|
-
console.warn(
|
|
61
|
-
|
|
129
|
+
if (legacyOptionNames.indexOf(name) !== -1) {
|
|
130
|
+
console.warn(
|
|
131
|
+
f(
|
|
132
|
+
'the server/replset/mongos options are deprecated, ' +
|
|
133
|
+
'all their options are supported at the top level of the options object [%s]',
|
|
134
|
+
validOptionNames
|
|
135
|
+
)
|
|
136
|
+
);
|
|
62
137
|
}
|
|
63
138
|
}
|
|
64
139
|
}
|
|
@@ -66,82 +141,87 @@ function validOptions(options) {
|
|
|
66
141
|
/**
|
|
67
142
|
* Creates a new MongoClient instance
|
|
68
143
|
* @class
|
|
69
|
-
* @
|
|
144
|
+
* @param {string} url The connection URI string
|
|
145
|
+
* @param {object} [options] Optional settings
|
|
146
|
+
* @param {number} [options.poolSize=5] The maximum size of the individual server pool
|
|
147
|
+
* @param {boolean} [options.ssl=false] Enable SSL connection.
|
|
148
|
+
* @param {boolean} [options.sslValidate=true] Validate mongod server certificate against Certificate Authority
|
|
149
|
+
* @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer
|
|
150
|
+
* @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer
|
|
151
|
+
* @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer
|
|
152
|
+
* @param {string} [options.sslPass=undefined] SSL Certificate pass phrase
|
|
153
|
+
* @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer
|
|
154
|
+
* @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
|
|
155
|
+
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
|
156
|
+
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
|
157
|
+
* @param {number} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
|
158
|
+
* @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
|
|
159
|
+
* @param {number} [options.family=null] Version of IP stack. Can be 4, 6 or null (default).
|
|
160
|
+
* If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
|
|
161
|
+
* @param {number} [options.socketTimeoutMS=360000] TCP Socket timeout setting
|
|
162
|
+
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
|
163
|
+
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
|
164
|
+
* @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
|
|
165
|
+
* @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
|
|
166
|
+
* @param {string} [options.replicaSet=undefined] The Replicaset set name
|
|
167
|
+
* @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
|
|
168
|
+
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
|
|
169
|
+
* @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
|
|
170
|
+
* @param {string} [options.authSource=undefined] Define the database to authenticate against
|
|
171
|
+
* @param {(number|string)} [options.w=null] The write concern
|
|
172
|
+
* @param {number} [options.wtimeout=null] The write concern timeout
|
|
173
|
+
* @param {boolean} [options.j=false] Specify a journal write concern
|
|
174
|
+
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
|
|
175
|
+
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
|
|
176
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
|
|
177
|
+
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers
|
|
178
|
+
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
|
|
179
|
+
* @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
|
|
180
|
+
* @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys
|
|
181
|
+
* @param {object} [options.promiseLibrary=null] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
|
|
182
|
+
* @param {object} [options.readConcern=null] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
|
|
183
|
+
* @param {string} [options.readConcern.level='local'] Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
|
|
184
|
+
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
|
|
185
|
+
* @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
|
|
186
|
+
* @param {object} [options.logger=undefined] Custom logger object
|
|
187
|
+
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
|
|
188
|
+
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
|
|
189
|
+
* @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
|
|
190
|
+
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
|
|
191
|
+
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function
|
|
192
|
+
* @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
|
|
193
|
+
* @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
|
|
194
|
+
* @param {string} [options.auth.user=undefined] The username for auth
|
|
195
|
+
* @param {string} [options.auth.password=undefined] The password for auth
|
|
196
|
+
* @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR
|
|
197
|
+
* @param {object} [options.compression=null] Type of compression to use: snappy or zlib
|
|
198
|
+
* @param {boolean} [options.fsync=false] Specify a file sync write concern
|
|
199
|
+
* @param {array} [options.readPreferenceTags=null] Read preference tags
|
|
200
|
+
* @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
|
|
201
|
+
* @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
|
|
202
|
+
* @param {MongoClient~connectCallback} [callback] The command result callback
|
|
203
|
+
* @return {MongoClient} a MongoClient instance
|
|
70
204
|
*/
|
|
71
|
-
function MongoClient() {
|
|
72
|
-
if(!(this instanceof MongoClient)) return new MongoClient();
|
|
205
|
+
function MongoClient(url, options) {
|
|
206
|
+
if (!(this instanceof MongoClient)) return new MongoClient();
|
|
73
207
|
|
|
74
208
|
// Set up event emitter
|
|
75
209
|
EventEmitter.call(this);
|
|
76
210
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
* @method
|
|
92
|
-
* @param {string} url The connection URI string
|
|
93
|
-
* @param {object} [options] Optional settings.
|
|
94
|
-
* @param {number} [options.poolSize=5] poolSize The maximum size of the individual server pool.
|
|
95
|
-
* @param {boolean} [options.ssl=false] Enable SSL connection.
|
|
96
|
-
* @param {Buffer} [options.sslCA=undefined] SSL Certificate store binary buffer
|
|
97
|
-
* @param {Buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer
|
|
98
|
-
* @param {Buffer} [options.sslCert=undefined] SSL Certificate binary buffer
|
|
99
|
-
* @param {Buffer} [options.sslKey=undefined] SSL Key file binary buffer
|
|
100
|
-
* @param {string} [options.sslPass=undefined] SSL Certificate pass phrase
|
|
101
|
-
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
|
|
102
|
-
* @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
|
|
103
|
-
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
|
104
|
-
* @param {number} [options.family=4] Version of IP stack. Defaults to 4.
|
|
105
|
-
* @param {number} [options.keepAlive=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket.
|
|
106
|
-
* @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
|
|
107
|
-
* @param {number} [options.socketTimeoutMS=360000] TCP Socket timeout setting
|
|
108
|
-
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
|
109
|
-
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
|
110
|
-
* @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies.
|
|
111
|
-
* @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
|
|
112
|
-
* @param {string} [options.replicaSet=undefined] The Replicaset set name
|
|
113
|
-
* @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
|
|
114
|
-
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection.
|
|
115
|
-
* @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
|
|
116
|
-
* @param {string} [options.authSource=undefined] Define the database to authenticate against
|
|
117
|
-
* @param {string} [options.auth.user=undefined] The username for auth
|
|
118
|
-
* @param {string} [options.auth.password=undefined] The password for auth
|
|
119
|
-
* @param {(number|string)} [options.w=null] The write concern.
|
|
120
|
-
* @param {number} [options.wtimeout=null] The write concern timeout.
|
|
121
|
-
* @param {boolean} [options.j=false] Specify a journal write concern.
|
|
122
|
-
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver.
|
|
123
|
-
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
|
|
124
|
-
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
125
|
-
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers.
|
|
126
|
-
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
|
127
|
-
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
|
128
|
-
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
|
129
|
-
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited.
|
|
130
|
-
* @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
|
131
|
-
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
|
132
|
-
* @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys.
|
|
133
|
-
* @param {object} [options.promiseLibrary=null] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
|
|
134
|
-
* @param {object} [options.readConcern=null] Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
|
|
135
|
-
* @param {string} [options.readConcern.level='local'] Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
|
|
136
|
-
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed);
|
|
137
|
-
* @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections.
|
|
138
|
-
* @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
|
|
139
|
-
* @param {object} [options.logger=undefined] Custom logger object
|
|
140
|
-
* @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness.
|
|
141
|
-
* @param {MongoClient~connectCallback} [callback] The command result callback
|
|
142
|
-
* @return {Promise} returns Promise if no callback passed
|
|
143
|
-
*/
|
|
144
|
-
this.connect = MongoClient.connect;
|
|
211
|
+
// The internal state
|
|
212
|
+
this.s = {
|
|
213
|
+
url: url,
|
|
214
|
+
options: options || {},
|
|
215
|
+
promiseLibrary: null,
|
|
216
|
+
dbCache: {},
|
|
217
|
+
sessions: []
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// Get the promiseLibrary
|
|
221
|
+
var promiseLibrary = this.s.options.promiseLibrary || Promise;
|
|
222
|
+
|
|
223
|
+
// Add the promise to the internal state
|
|
224
|
+
this.s.promiseLibrary = promiseLibrary;
|
|
145
225
|
}
|
|
146
226
|
|
|
147
227
|
/**
|
|
@@ -149,7 +229,183 @@ function MongoClient() {
|
|
|
149
229
|
*/
|
|
150
230
|
inherits(MongoClient, EventEmitter);
|
|
151
231
|
|
|
152
|
-
var define = MongoClient.define = new Define('MongoClient', MongoClient, false);
|
|
232
|
+
var define = (MongoClient.define = new Define('MongoClient', MongoClient, false));
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The callback format for results
|
|
236
|
+
* @callback MongoClient~connectCallback
|
|
237
|
+
* @param {MongoError} error An error instance representing the error during the execution.
|
|
238
|
+
* @param {MongoClient} client The connected client.
|
|
239
|
+
*/
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Connect to MongoDB using a url as documented at
|
|
243
|
+
*
|
|
244
|
+
* docs.mongodb.org/manual/reference/connection-string/
|
|
245
|
+
*
|
|
246
|
+
* Note that for replicasets the replicaSet query parameter is required in the 2.0 driver
|
|
247
|
+
*
|
|
248
|
+
* @method
|
|
249
|
+
* @param {MongoClient~connectCallback} [callback] The command result callback
|
|
250
|
+
* @return {Promise<MongoClient>} returns Promise if no callback passed
|
|
251
|
+
*/
|
|
252
|
+
MongoClient.prototype.connect = function(callback) {
|
|
253
|
+
// Validate options object
|
|
254
|
+
var err = validOptions(this.s.options);
|
|
255
|
+
|
|
256
|
+
if (typeof callback === 'string') {
|
|
257
|
+
throw new TypeError('`connect` only accepts a callback');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return executeOperation(this, connectOp, [this, err, callback], {
|
|
261
|
+
skipSessions: true
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const connectOp = (self, err, callback) => {
|
|
266
|
+
// Did we have a validation error
|
|
267
|
+
if (err) return callback(err);
|
|
268
|
+
// Fallback to callback based connect
|
|
269
|
+
connect(self, self.s.url, self.s.options, function(err) {
|
|
270
|
+
if (err) return callback(err);
|
|
271
|
+
callback(null, self);
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
define.classMethod('close', { callback: true, promise: true, returns: [MongoClient] });
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Logout user from server, fire off on all connections and remove all auth info
|
|
279
|
+
* @method
|
|
280
|
+
* @param {object} [options=null] Optional settings.
|
|
281
|
+
* @param {string} [options.dbName=null] Logout against different database than current.
|
|
282
|
+
* @param {Db~resultCallback} [callback] The command result callback
|
|
283
|
+
* @return {Promise} returns Promise if no callback passed
|
|
284
|
+
*/
|
|
285
|
+
MongoClient.prototype.logout = function(options, callback) {
|
|
286
|
+
if (typeof options === 'function') (callback = options), (options = {});
|
|
287
|
+
options = options || {};
|
|
288
|
+
|
|
289
|
+
// Establish the correct database name
|
|
290
|
+
var dbName = this.s.options.authSource ? this.s.options.authSource : this.s.options.dbName;
|
|
291
|
+
|
|
292
|
+
return executeOperation(this, logout, [this, dbName, callback], {
|
|
293
|
+
skipSessions: true
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const logout = (self, dbName, callback) => {
|
|
298
|
+
self.topology.logout(dbName, function(err) {
|
|
299
|
+
if (err) return callback(err);
|
|
300
|
+
callback(null, true);
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
define.classMethod('logout', { callback: true, promise: true });
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Close the db and its underlying connections
|
|
308
|
+
* @method
|
|
309
|
+
* @param {boolean} force Force close, emitting no events
|
|
310
|
+
* @param {Db~noResultCallback} [callback] The result callback
|
|
311
|
+
* @return {Promise} returns Promise if no callback passed
|
|
312
|
+
*/
|
|
313
|
+
MongoClient.prototype.close = function(force, callback) {
|
|
314
|
+
var self = this;
|
|
315
|
+
if (typeof force === 'function') (callback = force), (force = false);
|
|
316
|
+
// Close the topologu connection
|
|
317
|
+
this.topology.close(force);
|
|
318
|
+
|
|
319
|
+
// Emit close event
|
|
320
|
+
self.emit('close', self);
|
|
321
|
+
|
|
322
|
+
// Fire close event on any cached db instances
|
|
323
|
+
for (var name in this.s.dbCache) {
|
|
324
|
+
this.s.dbCache[name].emit('close');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Remove listeners after emit
|
|
328
|
+
self.removeAllListeners('close');
|
|
329
|
+
|
|
330
|
+
// If we have sessions, we want to send a single `endSessions` command for them,
|
|
331
|
+
// and then individually clean them up. They will be removed from the internal state
|
|
332
|
+
// when they emit their `ended` events.
|
|
333
|
+
if (this.s.sessions.length) {
|
|
334
|
+
this.topology.endSessions(this.s.sessions);
|
|
335
|
+
this.s.sessions.forEach(session => session.endSession({ skipCommand: true }));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Callback after next event loop tick
|
|
339
|
+
if (typeof callback === 'function')
|
|
340
|
+
return process.nextTick(function() {
|
|
341
|
+
handleCallback(callback, null);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Return dummy promise
|
|
345
|
+
return new this.s.promiseLibrary(function(resolve) {
|
|
346
|
+
resolve();
|
|
347
|
+
});
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
define.classMethod('close', { callback: true, promise: true });
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Create a new Db instance sharing the current socket connections. Be aware that the new db instances are
|
|
354
|
+
* related in a parent-child relationship to the original instance so that events are correctly emitted on child
|
|
355
|
+
* db instances. Child db instances are cached so performing db('db1') twice will return the same instance.
|
|
356
|
+
* You can control these behaviors with the options noListener and returnNonCachedInstance.
|
|
357
|
+
*
|
|
358
|
+
* @method
|
|
359
|
+
* @param {string} name The name of the database we want to use.
|
|
360
|
+
* @param {object} [options=null] Optional settings.
|
|
361
|
+
* @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
|
|
362
|
+
* @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
|
|
363
|
+
* @return {Db}
|
|
364
|
+
*/
|
|
365
|
+
MongoClient.prototype.db = function(dbName, options) {
|
|
366
|
+
options = options || {};
|
|
367
|
+
|
|
368
|
+
// Copy the options and add out internal override of the not shared flag
|
|
369
|
+
var finalOptions = Object.assign({}, this.s.options, options);
|
|
370
|
+
|
|
371
|
+
// Do we have the db in the cache already
|
|
372
|
+
if (this.s.dbCache[dbName] && finalOptions.returnNonCachedInstance !== true) {
|
|
373
|
+
return this.s.dbCache[dbName];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Add promiseLibrary
|
|
377
|
+
finalOptions.promiseLibrary = this.s.promiseLibrary;
|
|
378
|
+
|
|
379
|
+
// If no topology throw an error message
|
|
380
|
+
if (!this.topology) {
|
|
381
|
+
throw new MongoError('MongoClient must be connected before calling MongoClient.prototype.db');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Return the db object
|
|
385
|
+
var db = new Db(dbName, this.topology, finalOptions);
|
|
386
|
+
|
|
387
|
+
// Add the db to the cache
|
|
388
|
+
this.s.dbCache[dbName] = db;
|
|
389
|
+
// Return the database
|
|
390
|
+
return db;
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Check if MongoClient is connected
|
|
395
|
+
*
|
|
396
|
+
* @method
|
|
397
|
+
* @param {string} name The name of the database we want to use.
|
|
398
|
+
* @param {object} [options=null] Optional settings.
|
|
399
|
+
* @param {boolean} [options.noListener=false] Do not make the db an event listener to the original connection.
|
|
400
|
+
* @param {boolean} [options.returnNonCachedInstance=false] Control if you want to return a cached instance or have a new one created
|
|
401
|
+
* @return {boolean}
|
|
402
|
+
*/
|
|
403
|
+
MongoClient.prototype.isConnected = function(options) {
|
|
404
|
+
options = options || {};
|
|
405
|
+
|
|
406
|
+
if (!this.topology) return false;
|
|
407
|
+
return this.topology.isConnected(options);
|
|
408
|
+
};
|
|
153
409
|
|
|
154
410
|
/**
|
|
155
411
|
* Connect to MongoDB using a url as documented at
|
|
@@ -161,100 +417,109 @@ var define = MongoClient.define = new Define('MongoClient', MongoClient, false);
|
|
|
161
417
|
* @method
|
|
162
418
|
* @static
|
|
163
419
|
* @param {string} url The connection URI string
|
|
164
|
-
* @param {object} [options] Optional settings
|
|
165
|
-
* @param {number} [options.poolSize=5]
|
|
420
|
+
* @param {object} [options] Optional settings
|
|
421
|
+
* @param {number} [options.poolSize=5] The maximum size of the individual server pool
|
|
166
422
|
* @param {boolean} [options.ssl=false] Enable SSL connection.
|
|
167
|
-
* @param {
|
|
168
|
-
* @param {
|
|
169
|
-
* @param {
|
|
170
|
-
* @param {
|
|
423
|
+
* @param {boolean} [options.sslValidate=true] Validate mongod server certificate against Certificate Authority
|
|
424
|
+
* @param {buffer} [options.sslCA=undefined] SSL Certificate store binary buffer
|
|
425
|
+
* @param {buffer} [options.sslCert=undefined] SSL Certificate binary buffer
|
|
426
|
+
* @param {buffer} [options.sslKey=undefined] SSL Key file binary buffer
|
|
171
427
|
* @param {string} [options.sslPass=undefined] SSL Certificate pass phrase
|
|
172
|
-
* @param {
|
|
428
|
+
* @param {buffer} [options.sslCRL=undefined] SSL Certificate revocation list binary buffer
|
|
173
429
|
* @param {boolean} [options.autoReconnect=true] Enable autoReconnect for single server instances
|
|
174
430
|
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
|
175
|
-
* @param {
|
|
176
|
-
* @param {boolean} [options.
|
|
431
|
+
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
|
432
|
+
* @param {boolean} [options.keepAliveInitialDelay=30000] The number of milliseconds to wait before initiating keepAlive on the TCP socket
|
|
177
433
|
* @param {number} [options.connectTimeoutMS=30000] TCP Connection timeout setting
|
|
434
|
+
* @param {number} [options.family=null] Version of IP stack. Can be 4, 6 or null (default).
|
|
435
|
+
* If null, will attempt to connect with IPv6, and will fall back to IPv4 on failure
|
|
178
436
|
* @param {number} [options.socketTimeoutMS=360000] TCP Socket timeout setting
|
|
179
437
|
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
|
180
438
|
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
|
181
|
-
* @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
|
|
439
|
+
* @param {boolean} [options.ha=true] Control if high availability monitoring runs for Replicaset or Mongos proxies
|
|
182
440
|
* @param {number} [options.haInterval=10000] The High availability period for replicaset inquiry
|
|
183
441
|
* @param {string} [options.replicaSet=undefined] The Replicaset set name
|
|
184
442
|
* @param {number} [options.secondaryAcceptableLatencyMS=15] Cutoff latency point in MS for Replicaset member selection
|
|
185
|
-
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
|
|
443
|
+
* @param {number} [options.acceptableLatencyMS=15] Cutoff latency point in MS for Mongos proxies selection
|
|
186
444
|
* @param {boolean} [options.connectWithNoPrimary=false] Sets if the driver should connect even if no primary is available
|
|
187
445
|
* @param {string} [options.authSource=undefined] Define the database to authenticate against
|
|
188
|
-
* @param {string} [options.
|
|
189
|
-
* @param {
|
|
190
|
-
* @param {
|
|
191
|
-
* @param {
|
|
192
|
-
* @param {boolean} [options.
|
|
193
|
-
* @param {
|
|
194
|
-
* @param {boolean} [options.
|
|
195
|
-
* @param {
|
|
196
|
-
* @param {
|
|
197
|
-
* @param {
|
|
198
|
-
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
|
199
|
-
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
|
200
|
-
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited.
|
|
201
|
-
* @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
|
202
|
-
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
|
203
|
-
* @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys.
|
|
446
|
+
* @param {(number|string)} [options.w=null] The write concern
|
|
447
|
+
* @param {number} [options.wtimeout=null] The write concern timeout
|
|
448
|
+
* @param {boolean} [options.j=false] Specify a journal write concern
|
|
449
|
+
* @param {boolean} [options.forceServerObjectId=false] Force server to assign _id values instead of driver
|
|
450
|
+
* @param {boolean} [options.serializeFunctions=false] Serialize functions on any object
|
|
451
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields
|
|
452
|
+
* @param {boolean} [options.raw=false] Return document results as raw BSON buffers
|
|
453
|
+
* @param {number} [options.bufferMaxEntries=-1] Sets a cap on how many operations the driver will buffer up before giving up on getting a working connection, default is -1 which is unlimited
|
|
454
|
+
* @param {(ReadPreference|string)} [options.readPreference=null] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST)
|
|
455
|
+
* @param {object} [options.pkFactory=null] A primary key factory object for generation of custom _id keys
|
|
204
456
|
* @param {object} [options.promiseLibrary=null] A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible
|
|
205
|
-
* @param {object} [options.readConcern=null] Specify a read concern for the collection
|
|
457
|
+
* @param {object} [options.readConcern=null] Specify a read concern for the collection (only MongoDB 3.2 or higher supported)
|
|
206
458
|
* @param {string} [options.readConcern.level='local'] Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
|
|
207
|
-
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
|
|
208
|
-
* @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections.
|
|
459
|
+
* @param {number} [options.maxStalenessSeconds=undefined] The max staleness to secondary reads (values under 10 seconds cannot be guaranteed)
|
|
209
460
|
* @param {string} [options.loggerLevel=undefined] The logging level (error/warn/info/debug)
|
|
210
461
|
* @param {object} [options.logger=undefined] Custom logger object
|
|
211
|
-
* @param {
|
|
462
|
+
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types
|
|
463
|
+
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers
|
|
464
|
+
* @param {boolean} [options.promoteLongs=true] Promotes long values to number if they fit inside the 53 bits resolution
|
|
465
|
+
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit
|
|
466
|
+
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function
|
|
467
|
+
* @param {object} [options.validateOptions=false] Validate MongoClient passed in options for correctness
|
|
468
|
+
* @param {string} [options.appname=undefined] The name of the application that created this MongoClient instance. MongoDB 3.4 and newer will print this value in the server log upon establishing each connection. It is also recorded in the slow query log and profile collections
|
|
469
|
+
* @param {string} [options.auth.user=undefined] The username for auth
|
|
470
|
+
* @param {string} [options.auth.password=undefined] The password for auth
|
|
471
|
+
* @param {string} [options.authMechanism=undefined] Mechanism for authentication: MDEFAULT, GSSAPI, PLAIN, MONGODB-X509, SCRAM-SHA-1 or MONGODB-CR
|
|
472
|
+
* @param {object} [options.compression=null] Type of compression to use: snappy or zlib
|
|
473
|
+
* @param {boolean} [options.fsync=false] Specify a file sync write concern
|
|
474
|
+
* @param {array} [options.readPreferenceTags=null] Read preference tags
|
|
475
|
+
* @param {number} [options.numberOfRetries=5] The number of retries for a tailable cursor
|
|
476
|
+
* @param {boolean} [options.auto_reconnect=true] Enable auto reconnecting for single server instances
|
|
212
477
|
* @param {MongoClient~connectCallback} [callback] The command result callback
|
|
213
|
-
* @return {Promise} returns Promise if no callback passed
|
|
478
|
+
* @return {Promise<MongoClient>} returns Promise if no callback passed
|
|
214
479
|
*/
|
|
215
480
|
MongoClient.connect = function(url, options, callback) {
|
|
216
481
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
217
|
-
callback = typeof args[args.length - 1]
|
|
482
|
+
callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
|
|
218
483
|
options = args.length ? args.shift() : null;
|
|
219
484
|
options = options || {};
|
|
220
|
-
var self = this;
|
|
221
485
|
|
|
222
|
-
//
|
|
223
|
-
var
|
|
486
|
+
// Create client
|
|
487
|
+
var mongoClient = new MongoClient(url, options);
|
|
488
|
+
// Execute the connect method
|
|
489
|
+
return mongoClient.connect(callback);
|
|
490
|
+
};
|
|
224
491
|
|
|
225
|
-
|
|
226
|
-
var promiseLibrary = options.promiseLibrary;
|
|
492
|
+
define.staticMethod('connect', { callback: true, promise: true });
|
|
227
493
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
494
|
+
/**
|
|
495
|
+
* Starts a new session on the server
|
|
496
|
+
*
|
|
497
|
+
* @param {object} [options] optional settings for a driver session
|
|
498
|
+
* @param {MongoClient~sessionCallback} [callback] The callback called with a newly establish session, or an error if one occurred
|
|
499
|
+
* @return {Promise} if no callback is specified, a promise will be returned for the newly established session
|
|
500
|
+
*/
|
|
501
|
+
MongoClient.prototype.startSession = function(options) {
|
|
502
|
+
options = options || {};
|
|
503
|
+
if (!this.topology) {
|
|
504
|
+
throw new MongoError('Must connect to a server before calling this method');
|
|
232
505
|
}
|
|
233
506
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return new promiseLibrary(function(resolve, reject) {
|
|
237
|
-
// Did we have a validation error
|
|
238
|
-
if(err) return reject(err);
|
|
239
|
-
// Attempt to connect
|
|
240
|
-
connect(self, url, options, function(err, db) {
|
|
241
|
-
if(err) return reject(err);
|
|
242
|
-
resolve(db);
|
|
243
|
-
});
|
|
244
|
-
});
|
|
507
|
+
if (!this.topology.hasSessionSupport()) {
|
|
508
|
+
throw new MongoError('Current topology does not support sessions');
|
|
245
509
|
}
|
|
246
510
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
511
|
+
const session = this.topology.startSession(options);
|
|
512
|
+
session.once('ended', () => {
|
|
513
|
+
this.s.sessions = this.s.sessions.filter(s => s.equals(session));
|
|
514
|
+
});
|
|
252
515
|
|
|
253
|
-
|
|
516
|
+
this.s.sessions.push(session);
|
|
517
|
+
return session;
|
|
518
|
+
};
|
|
254
519
|
|
|
255
520
|
var mergeOptions = function(target, source, flatten) {
|
|
256
|
-
for(var name in source) {
|
|
257
|
-
if(source[name] && typeof source[name]
|
|
521
|
+
for (var name in source) {
|
|
522
|
+
if (source[name] && typeof source[name] === 'object' && flatten) {
|
|
258
523
|
target = mergeOptions(target, source[name], flatten);
|
|
259
524
|
} else {
|
|
260
525
|
target[name] = source[name];
|
|
@@ -262,20 +527,33 @@ var mergeOptions = function(target, source, flatten) {
|
|
|
262
527
|
}
|
|
263
528
|
|
|
264
529
|
return target;
|
|
265
|
-
}
|
|
530
|
+
};
|
|
266
531
|
|
|
267
532
|
var createUnifiedOptions = function(finalOptions, options) {
|
|
268
|
-
var childOptions = [
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
533
|
+
var childOptions = [
|
|
534
|
+
'mongos',
|
|
535
|
+
'server',
|
|
536
|
+
'db',
|
|
537
|
+
'replset',
|
|
538
|
+
'db_options',
|
|
539
|
+
'server_options',
|
|
540
|
+
'rs_options',
|
|
541
|
+
'mongos_options'
|
|
542
|
+
];
|
|
543
|
+
var noMerge = ['readconcern', 'compression'];
|
|
544
|
+
|
|
545
|
+
for (var name in options) {
|
|
546
|
+
if (noMerge.indexOf(name.toLowerCase()) !== -1) {
|
|
274
547
|
finalOptions[name] = options[name];
|
|
275
|
-
} else if(childOptions.indexOf(name.toLowerCase())
|
|
548
|
+
} else if (childOptions.indexOf(name.toLowerCase()) !== -1) {
|
|
276
549
|
finalOptions = mergeOptions(finalOptions, options[name], false);
|
|
277
550
|
} else {
|
|
278
|
-
if
|
|
551
|
+
if (
|
|
552
|
+
options[name] &&
|
|
553
|
+
typeof options[name] === 'object' &&
|
|
554
|
+
!Buffer.isBuffer(options[name]) &&
|
|
555
|
+
!Array.isArray(options[name])
|
|
556
|
+
) {
|
|
279
557
|
finalOptions = mergeOptions(finalOptions, options[name], true);
|
|
280
558
|
} else {
|
|
281
559
|
finalOptions[name] = options[name];
|
|
@@ -284,50 +562,69 @@ var createUnifiedOptions = function(finalOptions, options) {
|
|
|
284
562
|
}
|
|
285
563
|
|
|
286
564
|
return finalOptions;
|
|
287
|
-
}
|
|
565
|
+
};
|
|
288
566
|
|
|
289
567
|
function translateOptions(options) {
|
|
290
568
|
// If we have a readPreference passed in by the db options
|
|
291
|
-
if(typeof options.readPreference
|
|
569
|
+
if (typeof options.readPreference === 'string' || typeof options.read_preference === 'string') {
|
|
292
570
|
options.readPreference = new ReadPreference(options.readPreference || options.read_preference);
|
|
293
571
|
}
|
|
294
572
|
|
|
295
573
|
// Do we have readPreference tags, add them
|
|
296
|
-
if(options.readPreference && (options.readPreferenceTags || options.read_preference_tags)) {
|
|
574
|
+
if (options.readPreference && (options.readPreferenceTags || options.read_preference_tags)) {
|
|
297
575
|
options.readPreference.tags = options.readPreferenceTags || options.read_preference_tags;
|
|
298
576
|
}
|
|
299
577
|
|
|
300
578
|
// Do we have maxStalenessSeconds
|
|
301
|
-
if(options.maxStalenessSeconds) {
|
|
579
|
+
if (options.maxStalenessSeconds) {
|
|
302
580
|
options.readPreference.maxStalenessSeconds = options.maxStalenessSeconds;
|
|
303
581
|
}
|
|
304
582
|
|
|
305
583
|
// Set the socket and connection timeouts
|
|
306
|
-
if(options.socketTimeoutMS == null) options.socketTimeoutMS = 360000;
|
|
307
|
-
if(options.connectTimeoutMS == null) options.connectTimeoutMS = 30000;
|
|
584
|
+
if (options.socketTimeoutMS == null) options.socketTimeoutMS = 360000;
|
|
585
|
+
if (options.connectTimeoutMS == null) options.connectTimeoutMS = 30000;
|
|
308
586
|
|
|
309
587
|
// Create server instances
|
|
310
588
|
return options.servers.map(function(serverObj) {
|
|
311
|
-
return serverObj.domain_socket
|
|
312
|
-
new Server(serverObj.domain_socket, 27017, options)
|
|
313
|
-
|
|
589
|
+
return serverObj.domain_socket
|
|
590
|
+
? new Server(serverObj.domain_socket, 27017, options)
|
|
591
|
+
: new Server(serverObj.host, serverObj.port, options);
|
|
314
592
|
});
|
|
315
593
|
}
|
|
316
594
|
|
|
595
|
+
var events = [
|
|
596
|
+
'timeout',
|
|
597
|
+
'close',
|
|
598
|
+
'serverOpening',
|
|
599
|
+
'serverDescriptionChanged',
|
|
600
|
+
'serverHeartbeatStarted',
|
|
601
|
+
'serverHeartbeatSucceeded',
|
|
602
|
+
'serverHeartbeatFailed',
|
|
603
|
+
'serverClosed',
|
|
604
|
+
'topologyOpening',
|
|
605
|
+
'topologyClosed',
|
|
606
|
+
'topologyDescriptionChanged',
|
|
607
|
+
'joined',
|
|
608
|
+
'left',
|
|
609
|
+
'ping',
|
|
610
|
+
'ha',
|
|
611
|
+
'all',
|
|
612
|
+
'fullsetup'
|
|
613
|
+
];
|
|
614
|
+
|
|
317
615
|
//
|
|
318
616
|
// Collect all events in order from SDAM
|
|
319
617
|
//
|
|
320
|
-
function collectEvents(self,
|
|
618
|
+
function collectEvents(self, topology) {
|
|
321
619
|
var collectedEvents = [];
|
|
322
620
|
|
|
323
|
-
if(self instanceof MongoClient) {
|
|
324
|
-
var events = ["timeout", "close", 'serverOpening', 'serverDescriptionChanged', 'serverHeartbeatStarted',
|
|
325
|
-
'serverHeartbeatSucceeded', 'serverHeartbeatFailed', 'serverClosed', 'topologyOpening',
|
|
326
|
-
'topologyClosed', 'topologyDescriptionChanged', 'joined', 'left', 'ping', 'ha', 'all', 'fullsetup'];
|
|
621
|
+
if (self instanceof MongoClient) {
|
|
327
622
|
events.forEach(function(event) {
|
|
328
|
-
|
|
623
|
+
topology.on(event, function(object1, object2) {
|
|
329
624
|
collectedEvents.push({
|
|
330
|
-
event: event,
|
|
625
|
+
event: event,
|
|
626
|
+
object1: object1,
|
|
627
|
+
object2: object2
|
|
331
628
|
});
|
|
332
629
|
});
|
|
333
630
|
});
|
|
@@ -336,135 +633,213 @@ function collectEvents(self, db) {
|
|
|
336
633
|
return collectedEvents;
|
|
337
634
|
}
|
|
338
635
|
|
|
636
|
+
//
|
|
637
|
+
// Clear out all event
|
|
638
|
+
//
|
|
639
|
+
function clearAllEvents(topology) {
|
|
640
|
+
events.forEach(function(event) {
|
|
641
|
+
topology.removeAllListeners(event);
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
339
645
|
//
|
|
340
646
|
// Replay any events due to single server connection switching to Mongos
|
|
341
647
|
//
|
|
342
648
|
function replayEvents(self, events) {
|
|
343
|
-
for(var i = 0; i < events.length; i++) {
|
|
649
|
+
for (var i = 0; i < events.length; i++) {
|
|
344
650
|
self.emit(events[i].event, events[i].object1, events[i].object2);
|
|
345
651
|
}
|
|
346
652
|
}
|
|
347
653
|
|
|
348
|
-
function relayEvents(self,
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
654
|
+
function relayEvents(self, topology) {
|
|
655
|
+
var events = [
|
|
656
|
+
'serverOpening',
|
|
657
|
+
'serverDescriptionChanged',
|
|
658
|
+
'serverHeartbeatStarted',
|
|
659
|
+
'serverHeartbeatSucceeded',
|
|
660
|
+
'serverHeartbeatFailed',
|
|
661
|
+
'serverClosed',
|
|
662
|
+
'topologyOpening',
|
|
663
|
+
'topologyClosed',
|
|
664
|
+
'topologyDescriptionChanged',
|
|
665
|
+
'joined',
|
|
666
|
+
'left',
|
|
667
|
+
'ping',
|
|
668
|
+
'ha'
|
|
669
|
+
];
|
|
670
|
+
events.forEach(function(event) {
|
|
671
|
+
topology.on(event, function(object1, object2) {
|
|
672
|
+
self.emit(event, object1, object2);
|
|
357
673
|
});
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
function createReplicaset(self, options, callback) {
|
|
362
|
-
// Set default options
|
|
363
|
-
var servers = translateOptions(options);
|
|
364
|
-
// Create Db instance
|
|
365
|
-
var db = new Db(options.dbName, new ReplSet(servers, options), options);
|
|
366
|
-
// Propegate the events to the client
|
|
367
|
-
relayEvents(self, db);
|
|
368
|
-
// Open the connection
|
|
369
|
-
db.open(callback);
|
|
674
|
+
});
|
|
370
675
|
}
|
|
371
676
|
|
|
372
|
-
function
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
// Create Db instance
|
|
376
|
-
var db = new Db(options.dbName, new Mongos(servers, options), options)
|
|
377
|
-
// Propegate the events to the client
|
|
378
|
-
relayEvents(self, db);
|
|
379
|
-
// Open the connection
|
|
380
|
-
db.open(callback);
|
|
677
|
+
function assignTopology(client, topology) {
|
|
678
|
+
client.topology = topology;
|
|
679
|
+
topology.s.sessionPool = new ServerSessionPool(topology.s.coreTopology);
|
|
381
680
|
}
|
|
382
681
|
|
|
383
682
|
function createServer(self, options, callback) {
|
|
683
|
+
// Pass in the promise library
|
|
684
|
+
options.promiseLibrary = self.s.promiseLibrary;
|
|
685
|
+
|
|
384
686
|
// Set default options
|
|
385
687
|
var servers = translateOptions(options);
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
//
|
|
391
|
-
|
|
392
|
-
if(err) return callback(err);
|
|
688
|
+
|
|
689
|
+
// Propagate the events to the client
|
|
690
|
+
var collectedEvents = collectEvents(self, servers[0]);
|
|
691
|
+
|
|
692
|
+
// Connect to topology
|
|
693
|
+
servers[0].connect(function(err, topology) {
|
|
694
|
+
if (err) return callback(err);
|
|
695
|
+
// Clear out all the collected event listeners
|
|
696
|
+
clearAllEvents(servers[0]);
|
|
697
|
+
// Relay all the events
|
|
698
|
+
relayEvents(self, servers[0]);
|
|
699
|
+
// Add listeners
|
|
700
|
+
addListeners(self, servers[0]);
|
|
393
701
|
// Check if we are really speaking to a mongos
|
|
394
|
-
var ismaster =
|
|
702
|
+
var ismaster = topology.lastIsMaster();
|
|
703
|
+
|
|
704
|
+
// Set the topology
|
|
705
|
+
assignTopology(self, topology);
|
|
395
706
|
|
|
396
707
|
// Do we actually have a mongos
|
|
397
|
-
if(ismaster && ismaster.msg
|
|
708
|
+
if (ismaster && ismaster.msg === 'isdbgrid') {
|
|
398
709
|
// Destroy the current connection
|
|
399
|
-
|
|
710
|
+
topology.close();
|
|
400
711
|
// Create mongos connection instead
|
|
401
712
|
return createMongos(self, options, callback);
|
|
402
713
|
}
|
|
403
714
|
|
|
404
715
|
// Fire all the events
|
|
405
716
|
replayEvents(self, collectedEvents);
|
|
406
|
-
// Propegate the events to the client
|
|
407
|
-
relayEvents(self, db);
|
|
408
717
|
// Otherwise callback
|
|
409
|
-
callback(err,
|
|
718
|
+
callback(err, topology);
|
|
410
719
|
});
|
|
411
720
|
}
|
|
412
721
|
|
|
413
|
-
function
|
|
414
|
-
|
|
415
|
-
|
|
722
|
+
function createReplicaset(self, options, callback) {
|
|
723
|
+
// Pass in the promise library
|
|
724
|
+
options.promiseLibrary = self.s.promiseLibrary;
|
|
725
|
+
|
|
726
|
+
// Set default options
|
|
727
|
+
var servers = translateOptions(options);
|
|
728
|
+
|
|
729
|
+
// Create the topology
|
|
730
|
+
var topology = new ReplSet(servers, options);
|
|
731
|
+
|
|
732
|
+
// Add listeners
|
|
733
|
+
addListeners(self, topology);
|
|
734
|
+
|
|
735
|
+
// Propagate the events to the client
|
|
736
|
+
relayEvents(self, topology);
|
|
737
|
+
|
|
738
|
+
// Open the connection
|
|
739
|
+
topology.connect(options, function(err, topology) {
|
|
740
|
+
if (err) return callback(err);
|
|
741
|
+
|
|
742
|
+
assignTopology(self, topology);
|
|
743
|
+
callback(null, topology);
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
function createMongos(self, options, callback) {
|
|
748
|
+
// Pass in the promise library
|
|
749
|
+
options.promiseLibrary = self.s.promiseLibrary;
|
|
750
|
+
|
|
751
|
+
// Set default options
|
|
752
|
+
var servers = translateOptions(options);
|
|
753
|
+
|
|
754
|
+
// Create the topology
|
|
755
|
+
var topology = new Mongos(servers, options);
|
|
756
|
+
|
|
757
|
+
// Add listeners
|
|
758
|
+
addListeners(self, topology);
|
|
759
|
+
|
|
760
|
+
// Propagate the events to the client
|
|
761
|
+
relayEvents(self, topology);
|
|
762
|
+
|
|
763
|
+
// Open the connection
|
|
764
|
+
topology.connect(options, function(err, topology) {
|
|
765
|
+
if (err) return callback(err);
|
|
766
|
+
|
|
767
|
+
assignTopology(self, topology);
|
|
768
|
+
callback(null, topology);
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function createListener(self, event) {
|
|
773
|
+
return function(v1, v2) {
|
|
774
|
+
if (event === 'open' || event === 'fullsetup' || event === 'all' || event === 'reconnect') {
|
|
775
|
+
return self.emit(event, self);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
self.emit(event, v1, v2);
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function addListeners(self, topology) {
|
|
783
|
+
topology.on('authenticated', createListener(self, 'authenticated'));
|
|
784
|
+
topology.on('error', createListener(self, 'error'));
|
|
785
|
+
topology.on('timeout', createListener(self, 'timeout'));
|
|
786
|
+
topology.on('close', createListener(self, 'close'));
|
|
787
|
+
topology.on('parseError', createListener(self, 'parseError'));
|
|
788
|
+
topology.once('open', createListener(self, 'open'));
|
|
789
|
+
topology.once('fullsetup', createListener(self, 'fullsetup'));
|
|
790
|
+
topology.once('all', createListener(self, 'all'));
|
|
791
|
+
topology.on('reconnect', createListener(self, 'reconnect'));
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
function connectHandler(client, options, callback) {
|
|
795
|
+
return function(err, topology) {
|
|
796
|
+
if (err) {
|
|
416
797
|
return process.nextTick(function() {
|
|
417
798
|
try {
|
|
418
799
|
callback(err, null);
|
|
419
800
|
} catch (err) {
|
|
420
|
-
if(
|
|
421
|
-
throw err
|
|
801
|
+
if (topology) topology.close();
|
|
802
|
+
throw err;
|
|
422
803
|
}
|
|
423
804
|
});
|
|
424
805
|
}
|
|
425
806
|
|
|
426
807
|
// No authentication just reconnect
|
|
427
|
-
if(!options.auth) {
|
|
808
|
+
if (!options.auth) {
|
|
428
809
|
return process.nextTick(function() {
|
|
429
810
|
try {
|
|
430
|
-
callback(err,
|
|
811
|
+
callback(err, topology);
|
|
431
812
|
} catch (err) {
|
|
432
|
-
if(
|
|
433
|
-
throw err
|
|
813
|
+
if (topology) topology.close();
|
|
814
|
+
throw err;
|
|
434
815
|
}
|
|
435
|
-
})
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// What db to authenticate against
|
|
439
|
-
var authentication_db = db;
|
|
440
|
-
if(options.authSource) {
|
|
441
|
-
authentication_db = db.db(options.authSource);
|
|
816
|
+
});
|
|
442
817
|
}
|
|
443
818
|
|
|
444
819
|
// Authenticate
|
|
445
|
-
authenticate(
|
|
446
|
-
if(success){
|
|
820
|
+
authenticate(client, options.user, options.password, options, function(err, success) {
|
|
821
|
+
if (success) {
|
|
447
822
|
process.nextTick(function() {
|
|
448
823
|
try {
|
|
449
|
-
callback(null,
|
|
824
|
+
callback(null, topology);
|
|
450
825
|
} catch (err) {
|
|
451
|
-
if(
|
|
452
|
-
throw err
|
|
826
|
+
if (topology) topology.close();
|
|
827
|
+
throw err;
|
|
453
828
|
}
|
|
454
829
|
});
|
|
455
830
|
} else {
|
|
456
|
-
if(
|
|
831
|
+
if (topology) topology.close();
|
|
457
832
|
process.nextTick(function() {
|
|
458
833
|
try {
|
|
459
834
|
callback(err ? err : new Error('Could not authenticate user ' + options.auth[0]), null);
|
|
460
835
|
} catch (err) {
|
|
461
|
-
if(
|
|
462
|
-
throw err
|
|
836
|
+
if (topology) topology.close();
|
|
837
|
+
throw err;
|
|
463
838
|
}
|
|
464
839
|
});
|
|
465
840
|
}
|
|
466
841
|
});
|
|
467
|
-
}
|
|
842
|
+
};
|
|
468
843
|
}
|
|
469
844
|
|
|
470
845
|
/*
|
|
@@ -475,14 +850,39 @@ var connect = function(self, url, options, callback) {
|
|
|
475
850
|
options = shallowClone(options);
|
|
476
851
|
|
|
477
852
|
// If callback is null throw an exception
|
|
478
|
-
if(callback == null) {
|
|
479
|
-
throw new Error(
|
|
853
|
+
if (callback == null) {
|
|
854
|
+
throw new Error('no callback function provided');
|
|
480
855
|
}
|
|
481
856
|
|
|
482
857
|
// Get a logger for MongoClient
|
|
483
858
|
var logger = Logger('MongoClient', options);
|
|
484
859
|
|
|
860
|
+
// Did we pass in a Server/ReplSet/Mongos
|
|
861
|
+
if (url instanceof Server || url instanceof ReplSet || url instanceof Mongos) {
|
|
862
|
+
// Set the topology
|
|
863
|
+
assignTopology(self, url);
|
|
864
|
+
|
|
865
|
+
// Add listeners
|
|
866
|
+
addListeners(self, url);
|
|
867
|
+
// Connect
|
|
868
|
+
return url.connect(
|
|
869
|
+
options,
|
|
870
|
+
connectHandler(self, options, function(err, topology) {
|
|
871
|
+
if (err) return connectCallback(err, topology);
|
|
872
|
+
if (options.user || options.password || options.authMechanism) {
|
|
873
|
+
return authenticate(self, options.user, options.password, options, function(err) {
|
|
874
|
+
if (err) return connectCallback(err, topology);
|
|
875
|
+
connectCallback(err, topology);
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
connectCallback(err, topology);
|
|
880
|
+
})
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
|
|
485
884
|
parse(url, options, function(err, object) {
|
|
885
|
+
// Do not attempt to connect if parsing error
|
|
486
886
|
if (err) return callback(err);
|
|
487
887
|
|
|
488
888
|
// Parse the string
|
|
@@ -491,41 +891,64 @@ var connect = function(self, url, options, callback) {
|
|
|
491
891
|
_finalOptions = createUnifiedOptions(_finalOptions, options);
|
|
492
892
|
|
|
493
893
|
// Check if we have connection and socket timeout set
|
|
494
|
-
if(_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 360000;
|
|
495
|
-
if(_finalOptions.connectTimeoutMS == null) _finalOptions.connectTimeoutMS = 30000;
|
|
894
|
+
if (_finalOptions.socketTimeoutMS == null) _finalOptions.socketTimeoutMS = 360000;
|
|
895
|
+
if (_finalOptions.connectTimeoutMS == null) _finalOptions.connectTimeoutMS = 30000;
|
|
496
896
|
|
|
497
897
|
if (_finalOptions.db_options && _finalOptions.db_options.auth) {
|
|
498
898
|
delete _finalOptions.db_options.auth;
|
|
499
899
|
}
|
|
500
900
|
|
|
901
|
+
// Store the merged options object
|
|
902
|
+
self.s.options = _finalOptions;
|
|
903
|
+
|
|
501
904
|
// Failure modes
|
|
502
|
-
if(object.servers.length
|
|
503
|
-
|
|
905
|
+
if (object.servers.length === 0) {
|
|
906
|
+
return callback(new Error('connection string must contain at least one seed host'));
|
|
504
907
|
}
|
|
505
908
|
|
|
506
909
|
// Do we have a replicaset then skip discovery and go straight to connectivity
|
|
507
|
-
if(_finalOptions.replicaSet || _finalOptions.rs_name) {
|
|
508
|
-
return createReplicaset(
|
|
509
|
-
|
|
510
|
-
|
|
910
|
+
if (_finalOptions.replicaSet || _finalOptions.rs_name) {
|
|
911
|
+
return createReplicaset(
|
|
912
|
+
self,
|
|
913
|
+
_finalOptions,
|
|
914
|
+
connectHandler(self, _finalOptions, connectCallback)
|
|
915
|
+
);
|
|
916
|
+
} else if (object.servers.length > 1) {
|
|
917
|
+
return createMongos(
|
|
918
|
+
self,
|
|
919
|
+
_finalOptions,
|
|
920
|
+
connectHandler(self, _finalOptions, connectCallback)
|
|
921
|
+
);
|
|
511
922
|
} else {
|
|
512
|
-
return createServer(
|
|
923
|
+
return createServer(
|
|
924
|
+
self,
|
|
925
|
+
_finalOptions,
|
|
926
|
+
connectHandler(self, _finalOptions, connectCallback)
|
|
927
|
+
);
|
|
513
928
|
}
|
|
514
929
|
});
|
|
515
930
|
|
|
516
|
-
function connectCallback(err,
|
|
517
|
-
if(err && err.message
|
|
518
|
-
if(logger.isWarn()) {
|
|
519
|
-
logger.warn(
|
|
931
|
+
function connectCallback(err, topology) {
|
|
932
|
+
if (err && err.message === 'no mongos proxies found in seed list') {
|
|
933
|
+
if (logger.isWarn()) {
|
|
934
|
+
logger.warn(
|
|
935
|
+
f(
|
|
936
|
+
'seed list contains no mongos proxies, replicaset connections requires the parameter replicaSet to be supplied in the URI or options object, mongodb://server:port/db?replicaSet=name'
|
|
937
|
+
)
|
|
938
|
+
);
|
|
520
939
|
}
|
|
521
940
|
|
|
522
941
|
// Return a more specific error message for MongoClient.connect
|
|
523
|
-
return callback(
|
|
942
|
+
return callback(
|
|
943
|
+
new MongoError(
|
|
944
|
+
'seed list contains no mongos proxies, replicaset connections requires the parameter replicaSet to be supplied in the URI or options object, mongodb://server:port/db?replicaSet=name'
|
|
945
|
+
)
|
|
946
|
+
);
|
|
524
947
|
}
|
|
525
948
|
|
|
526
949
|
// Return the error and db instance
|
|
527
|
-
callback(err,
|
|
950
|
+
callback(err, topology);
|
|
528
951
|
}
|
|
529
|
-
}
|
|
952
|
+
};
|
|
530
953
|
|
|
531
|
-
module.exports = MongoClient
|
|
954
|
+
module.exports = MongoClient;
|