mongodb 3.5.9 → 3.5.10
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 +12 -1
- package/lib/change_stream.js +7 -2
- package/lib/collection.js +2 -3
- package/lib/core/cursor.js +30 -39
- package/lib/core/sdam/monitor.js +2 -3
- package/lib/core/sdam/server.js +1 -2
- package/lib/core/sdam/server_description.js +10 -0
- package/lib/core/sdam/topology.js +4 -26
- package/lib/core/sessions.js +5 -0
- package/lib/core/topologies/read_preference.js +58 -6
- package/lib/core/wireprotocol/command.js +1 -6
- package/lib/db.js +3 -3
- package/lib/operations/collection_ops.js +1 -2
- package/lib/operations/command.js +2 -3
- package/lib/operations/command_v2.js +7 -6
- package/lib/operations/db_ops.js +1 -2
- package/lib/operations/find.js +2 -2
- package/lib/operations/geo_haystack_search.js +2 -2
- package/lib/operations/map_reduce.js +2 -2
- package/lib/operations/operation.js +2 -1
- package/lib/operations/run_command.js +19 -0
- package/lib/topologies/topology_base.js +4 -4
- package/lib/utils.js +0 -59
- package/package.json +2 -2
package/HISTORY.md
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Changelog
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [3.5.10](https://github.com/mongodb/node-mongodb-native/compare/v3.5.9...v3.5.10) (2020-07-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* db.command to not inherit options from parent ([f7a50e2](https://github.com/mongodb/node-mongodb-native/commit/f7a50e2f43375cc411d6f521e3b103c96ceca51a))
|
|
11
|
+
* ipv6 is not supported when using dns service discovery ([a1be593](https://github.com/mongodb/node-mongodb-native/commit/a1be59315c3dc65a04d3f83bb75fff2f1b9c16ef))
|
|
12
|
+
* ReadPreference maxStalenessSeconds from options ([72a743d](https://github.com/mongodb/node-mongodb-native/commit/72a743d536181867f770a88ea9cd68d30b3f97fd))
|
|
13
|
+
* silently ignore session with unacknowledged write ([8f1ea7b](https://github.com/mongodb/node-mongodb-native/commit/8f1ea7b69678c243a729267109ac3e50387914f8))
|
|
14
|
+
* **ChangeStream:** handle null changes ([306b5b3](https://github.com/mongodb/node-mongodb-native/commit/306b5b3f7103f91c6c07c08f95375876093ad897))
|
|
15
|
+
|
|
5
16
|
<a name="3.5.9"></a>
|
|
6
17
|
## [3.5.9](https://github.com/mongodb/node-mongodb-native/compare/v3.5.8...v3.5.9) (2020-06-12)
|
|
7
18
|
|
package/lib/change_stream.js
CHANGED
|
@@ -326,8 +326,8 @@ class ChangeStreamCursor extends Cursor {
|
|
|
326
326
|
|
|
327
327
|
_initializeCursor(callback) {
|
|
328
328
|
super._initializeCursor((err, result) => {
|
|
329
|
-
if (err) {
|
|
330
|
-
callback(err);
|
|
329
|
+
if (err || result == null) {
|
|
330
|
+
callback(err, result);
|
|
331
331
|
return;
|
|
332
332
|
}
|
|
333
333
|
|
|
@@ -483,6 +483,11 @@ function waitForTopologyConnected(topology, options, callback) {
|
|
|
483
483
|
function processNewChange(changeStream, change, callback) {
|
|
484
484
|
const cursor = changeStream.cursor;
|
|
485
485
|
|
|
486
|
+
// a null change means the cursor has been notified, implicitly closing the change stream
|
|
487
|
+
if (change == null) {
|
|
488
|
+
changeStream.closed = true;
|
|
489
|
+
}
|
|
490
|
+
|
|
486
491
|
if (changeStream.closed) {
|
|
487
492
|
if (callback) callback(new MongoError('ChangeStream is closed'));
|
|
488
493
|
return;
|
package/lib/collection.js
CHANGED
|
@@ -16,7 +16,6 @@ const unordered = require('./bulk/unordered');
|
|
|
16
16
|
const ordered = require('./bulk/ordered');
|
|
17
17
|
const ChangeStream = require('./change_stream');
|
|
18
18
|
const executeLegacyOperation = require('./utils').executeLegacyOperation;
|
|
19
|
-
const resolveReadPreference = require('./utils').resolveReadPreference;
|
|
20
19
|
const WriteConcern = require('./write_concern');
|
|
21
20
|
const ReadConcern = require('./read_concern');
|
|
22
21
|
const MongoDBNamespace = require('./utils').MongoDBNamespace;
|
|
@@ -399,7 +398,7 @@ Collection.prototype.find = deprecateOptions(
|
|
|
399
398
|
newOptions.slaveOk = options.slaveOk != null ? options.slaveOk : this.s.db.slaveOk;
|
|
400
399
|
|
|
401
400
|
// Add read preference if needed
|
|
402
|
-
newOptions.readPreference =
|
|
401
|
+
newOptions.readPreference = ReadPreference.resolve(this, newOptions);
|
|
403
402
|
|
|
404
403
|
// Set slave ok to true if read preference different from primary
|
|
405
404
|
if (
|
|
@@ -1978,7 +1977,7 @@ Collection.prototype.parallelCollectionScan = deprecate(function(options, callba
|
|
|
1978
1977
|
|
|
1979
1978
|
options = Object.assign({}, options);
|
|
1980
1979
|
// Ensure we have the right read preference inheritance
|
|
1981
|
-
options.readPreference =
|
|
1980
|
+
options.readPreference = ReadPreference.resolve(this, options);
|
|
1982
1981
|
|
|
1983
1982
|
// Add a promiseLibrary
|
|
1984
1983
|
options.promiseLibrary = this.s.promiseLibrary;
|
package/lib/core/cursor.js
CHANGED
|
@@ -464,50 +464,41 @@ class CoreCursor extends Readable {
|
|
|
464
464
|
}
|
|
465
465
|
|
|
466
466
|
const result = r.message;
|
|
467
|
-
if (result.queryFailure) {
|
|
468
|
-
return done(new MongoError(result.documents[0]), null);
|
|
469
|
-
}
|
|
470
467
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
result.
|
|
475
|
-
|
|
476
|
-
(typeof result.documents[0].cursor !== 'string' ||
|
|
477
|
-
result.documents[0]['$err'] ||
|
|
478
|
-
result.documents[0]['errmsg'] ||
|
|
479
|
-
Array.isArray(result.documents[0].result))
|
|
480
|
-
) {
|
|
481
|
-
// We have an error document, return the error
|
|
482
|
-
if (result.documents[0]['$err'] || result.documents[0]['errmsg']) {
|
|
483
|
-
return done(new MongoError(result.documents[0]), null);
|
|
468
|
+
if (Array.isArray(result.documents) && result.documents.length === 1) {
|
|
469
|
+
const document = result.documents[0];
|
|
470
|
+
|
|
471
|
+
if (result.queryFailure) {
|
|
472
|
+
return done(new MongoError(document), null);
|
|
484
473
|
}
|
|
485
474
|
|
|
486
|
-
//
|
|
487
|
-
if (
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
cursor.ns = result.documents[0].cursor.ns;
|
|
475
|
+
// Check if we have a command cursor
|
|
476
|
+
if (!cursor.cmd.find || (cursor.cmd.find && cursor.cmd.virtual === false)) {
|
|
477
|
+
// We have an error document, return the error
|
|
478
|
+
if (document.$err || document.errmsg) {
|
|
479
|
+
return done(new MongoError(document), null);
|
|
492
480
|
}
|
|
493
|
-
// Promote id to long if needed
|
|
494
|
-
cursor.cursorState.cursorId = typeof id === 'number' ? Long.fromNumber(id) : id;
|
|
495
|
-
cursor.cursorState.lastCursorId = cursor.cursorState.cursorId;
|
|
496
|
-
cursor.cursorState.operationTime = result.documents[0].operationTime;
|
|
497
|
-
|
|
498
|
-
// If we have a firstBatch set it
|
|
499
|
-
if (Array.isArray(result.documents[0].cursor.firstBatch)) {
|
|
500
|
-
cursor.cursorState.documents = result.documents[0].cursor.firstBatch; //.reverse();
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Return after processing command cursor
|
|
504
|
-
return done(null, result);
|
|
505
|
-
}
|
|
506
481
|
|
|
507
|
-
|
|
508
|
-
cursor.
|
|
509
|
-
|
|
510
|
-
|
|
482
|
+
// We have a cursor document
|
|
483
|
+
if (document.cursor != null && typeof document.cursor !== 'string') {
|
|
484
|
+
const id = document.cursor.id;
|
|
485
|
+
// If we have a namespace change set the new namespace for getmores
|
|
486
|
+
if (document.cursor.ns) {
|
|
487
|
+
cursor.ns = document.cursor.ns;
|
|
488
|
+
}
|
|
489
|
+
// Promote id to long if needed
|
|
490
|
+
cursor.cursorState.cursorId = typeof id === 'number' ? Long.fromNumber(id) : id;
|
|
491
|
+
cursor.cursorState.lastCursorId = cursor.cursorState.cursorId;
|
|
492
|
+
cursor.cursorState.operationTime = document.operationTime;
|
|
493
|
+
|
|
494
|
+
// If we have a firstBatch set it
|
|
495
|
+
if (Array.isArray(document.cursor.firstBatch)) {
|
|
496
|
+
cursor.cursorState.documents = document.cursor.firstBatch; //.reverse();
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Return after processing command cursor
|
|
500
|
+
return done(null, result);
|
|
501
|
+
}
|
|
511
502
|
}
|
|
512
503
|
}
|
|
513
504
|
|
package/lib/core/sdam/monitor.js
CHANGED
|
@@ -66,13 +66,12 @@ class Monitor extends EventEmitter {
|
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
// TODO: refactor this to pull it directly from the pool, requires new ConnectionPool integration
|
|
69
|
-
const addressParts = server.description.address.split(':');
|
|
70
69
|
this.connectOptions = Object.freeze(
|
|
71
70
|
Object.assign(
|
|
72
71
|
{
|
|
73
72
|
id: '<monitor>',
|
|
74
|
-
host:
|
|
75
|
-
port:
|
|
73
|
+
host: server.description.host,
|
|
74
|
+
port: server.description.port,
|
|
76
75
|
bson: server.s.bson,
|
|
77
76
|
connectionType: Connection
|
|
78
77
|
},
|
package/lib/core/sdam/server.js
CHANGED
|
@@ -110,9 +110,8 @@ class Server extends EventEmitter {
|
|
|
110
110
|
|
|
111
111
|
// create the connection pool
|
|
112
112
|
// NOTE: this used to happen in `connect`, we supported overriding pool options there
|
|
113
|
-
const addressParts = this.description.address.split(':');
|
|
114
113
|
const poolOptions = Object.assign(
|
|
115
|
-
{ host:
|
|
114
|
+
{ host: this.description.host, port: this.description.port, bson: this.s.bson },
|
|
116
115
|
options
|
|
117
116
|
);
|
|
118
117
|
|
|
@@ -113,6 +113,16 @@ class ServerDescription {
|
|
|
113
113
|
return WRITABLE_SERVER_TYPES.has(this.type);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
get host() {
|
|
117
|
+
const chopLength = `:${this.port}`.length;
|
|
118
|
+
return this.address.slice(0, -chopLength);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get port() {
|
|
122
|
+
const port = this.address.split(':').pop();
|
|
123
|
+
return port ? Number.parseInt(port, 10) : port;
|
|
124
|
+
}
|
|
125
|
+
|
|
116
126
|
/**
|
|
117
127
|
* Determines if another `ServerDescription` is equal to this one per the rules defined
|
|
118
128
|
* in the {@link https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#serverdescription|SDAM spec}
|
|
@@ -275,7 +275,7 @@ class Topology extends EventEmitter {
|
|
|
275
275
|
// connect all known servers, then attempt server selection to connect
|
|
276
276
|
connectServers(this, Array.from(this.s.description.servers.values()));
|
|
277
277
|
|
|
278
|
-
|
|
278
|
+
ReadPreference.translate(options);
|
|
279
279
|
const readPreference = options.readPreference || ReadPreference.primary;
|
|
280
280
|
this.selectServer(readPreferenceServerSelector(readPreference), options, err => {
|
|
281
281
|
if (err) {
|
|
@@ -381,7 +381,7 @@ class Topology extends EventEmitter {
|
|
|
381
381
|
} else if (typeof selector === 'string') {
|
|
382
382
|
readPreference = new ReadPreference(selector);
|
|
383
383
|
} else {
|
|
384
|
-
|
|
384
|
+
ReadPreference.translate(options);
|
|
385
385
|
readPreference = options.readPreference || ReadPreference.primary;
|
|
386
386
|
}
|
|
387
387
|
|
|
@@ -647,7 +647,7 @@ class Topology extends EventEmitter {
|
|
|
647
647
|
(callback = options), (options = {}), (options = options || {});
|
|
648
648
|
}
|
|
649
649
|
|
|
650
|
-
|
|
650
|
+
ReadPreference.translate(options);
|
|
651
651
|
const readPreference = options.readPreference || ReadPreference.primary;
|
|
652
652
|
|
|
653
653
|
this.selectServer(readPreferenceServerSelector(readPreference), options, (err, server) => {
|
|
@@ -708,7 +708,7 @@ class Topology extends EventEmitter {
|
|
|
708
708
|
options = options || {};
|
|
709
709
|
const topology = options.topology || this;
|
|
710
710
|
const CursorClass = options.cursorFactory || this.s.Cursor;
|
|
711
|
-
|
|
711
|
+
ReadPreference.translate(options);
|
|
712
712
|
|
|
713
713
|
return new CursorClass(topology, ns, cmd, options);
|
|
714
714
|
}
|
|
@@ -939,28 +939,6 @@ function executeWriteOperation(args, options, callback) {
|
|
|
939
939
|
});
|
|
940
940
|
}
|
|
941
941
|
|
|
942
|
-
function translateReadPreference(options) {
|
|
943
|
-
if (options.readPreference == null) {
|
|
944
|
-
return;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
let r = options.readPreference;
|
|
948
|
-
if (typeof r === 'string') {
|
|
949
|
-
options.readPreference = new ReadPreference(r);
|
|
950
|
-
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
|
951
|
-
const mode = r.mode || r.preference;
|
|
952
|
-
if (mode && typeof mode === 'string') {
|
|
953
|
-
options.readPreference = new ReadPreference(mode, r.tags, {
|
|
954
|
-
maxStalenessSeconds: r.maxStalenessSeconds
|
|
955
|
-
});
|
|
956
|
-
}
|
|
957
|
-
} else if (!(r instanceof ReadPreference)) {
|
|
958
|
-
throw new TypeError('Invalid read preference: ' + r);
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
return options;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
942
|
function srvPollingHandler(topology) {
|
|
965
943
|
return function handleSrvPolling(ev) {
|
|
966
944
|
const previousTopologyDescription = topology.s.description;
|
package/lib/core/sessions.js
CHANGED
|
@@ -708,6 +708,11 @@ function applySession(session, command, options) {
|
|
|
708
708
|
return new MongoError('Cannot use a session that has ended');
|
|
709
709
|
}
|
|
710
710
|
|
|
711
|
+
// SPEC-1019: silently ignore explicit session with unacknowledged write for backwards compatibility
|
|
712
|
+
if (options && options.writeConcern && options.writeConcern.w === 0) {
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
|
|
711
716
|
const serverSession = session.serverSession;
|
|
712
717
|
serverSession.lastUse = now();
|
|
713
718
|
command.lsid = serverSession.id;
|
|
@@ -91,20 +91,18 @@ const VALID_MODES = [
|
|
|
91
91
|
* @return {ReadPreference}
|
|
92
92
|
*/
|
|
93
93
|
ReadPreference.fromOptions = function(options) {
|
|
94
|
+
if (!options) return null;
|
|
94
95
|
const readPreference = options.readPreference;
|
|
96
|
+
if (readPreference == null) return null;
|
|
95
97
|
const readPreferenceTags = options.readPreferenceTags;
|
|
96
|
-
|
|
97
|
-
if (readPreference == null) {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
98
|
+
const maxStalenessSeconds = options.maxStalenessSeconds;
|
|
101
99
|
if (typeof readPreference === 'string') {
|
|
102
100
|
return new ReadPreference(readPreference, readPreferenceTags);
|
|
103
101
|
} else if (!(readPreference instanceof ReadPreference) && typeof readPreference === 'object') {
|
|
104
102
|
const mode = readPreference.mode || readPreference.preference;
|
|
105
103
|
if (mode && typeof mode === 'string') {
|
|
106
104
|
return new ReadPreference(mode, readPreference.tags, {
|
|
107
|
-
maxStalenessSeconds: readPreference.maxStalenessSeconds
|
|
105
|
+
maxStalenessSeconds: readPreference.maxStalenessSeconds || maxStalenessSeconds
|
|
108
106
|
});
|
|
109
107
|
}
|
|
110
108
|
}
|
|
@@ -112,6 +110,60 @@ ReadPreference.fromOptions = function(options) {
|
|
|
112
110
|
return readPreference;
|
|
113
111
|
};
|
|
114
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Resolves a read preference based on well-defined inheritance rules. This method will not only
|
|
115
|
+
* determine the read preference (if there is one), but will also ensure the returned value is a
|
|
116
|
+
* properly constructed instance of `ReadPreference`.
|
|
117
|
+
*
|
|
118
|
+
* @param {Collection|Db|MongoClient} parent The parent of the operation on which to determine the read
|
|
119
|
+
* preference, used for determining the inherited read preference.
|
|
120
|
+
* @param {object} options The options passed into the method, potentially containing a read preference
|
|
121
|
+
* @returns {(ReadPreference|null)} The resolved read preference
|
|
122
|
+
*/
|
|
123
|
+
ReadPreference.resolve = function(parent, options) {
|
|
124
|
+
options = options || {};
|
|
125
|
+
const session = options.session;
|
|
126
|
+
|
|
127
|
+
const inheritedReadPreference = parent && parent.readPreference;
|
|
128
|
+
|
|
129
|
+
let readPreference;
|
|
130
|
+
if (options.readPreference) {
|
|
131
|
+
readPreference = ReadPreference.fromOptions(options);
|
|
132
|
+
} else if (session && session.inTransaction() && session.transaction.options.readPreference) {
|
|
133
|
+
// The transaction’s read preference MUST override all other user configurable read preferences.
|
|
134
|
+
readPreference = session.transaction.options.readPreference;
|
|
135
|
+
} else if (inheritedReadPreference != null) {
|
|
136
|
+
readPreference = inheritedReadPreference;
|
|
137
|
+
} else {
|
|
138
|
+
readPreference = ReadPreference.primary;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return typeof readPreference === 'string' ? new ReadPreference(readPreference) : readPreference;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Replaces options.readPreference with a ReadPreference instance
|
|
146
|
+
*/
|
|
147
|
+
ReadPreference.translate = function(options) {
|
|
148
|
+
if (options.readPreference == null) return options;
|
|
149
|
+
const r = options.readPreference;
|
|
150
|
+
|
|
151
|
+
if (typeof r === 'string') {
|
|
152
|
+
options.readPreference = new ReadPreference(r);
|
|
153
|
+
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
|
154
|
+
const mode = r.mode || r.preference;
|
|
155
|
+
if (mode && typeof mode === 'string') {
|
|
156
|
+
options.readPreference = new ReadPreference(mode, r.tags, {
|
|
157
|
+
maxStalenessSeconds: r.maxStalenessSeconds
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
} else if (!(r instanceof ReadPreference)) {
|
|
161
|
+
throw new TypeError('Invalid read preference: ' + r);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return options;
|
|
165
|
+
};
|
|
166
|
+
|
|
115
167
|
/**
|
|
116
168
|
* Validate if a mode is legal
|
|
117
169
|
*
|
|
@@ -66,12 +66,7 @@ function _command(server, ns, cmd, options, callback) {
|
|
|
66
66
|
finalCmd.$clusterTime = clusterTime;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
if (
|
|
70
|
-
isSharded(server) &&
|
|
71
|
-
!shouldUseOpMsg &&
|
|
72
|
-
readPreference &&
|
|
73
|
-
readPreference.preference !== 'primary'
|
|
74
|
-
) {
|
|
69
|
+
if (isSharded(server) && !shouldUseOpMsg && readPreference && readPreference.mode !== 'primary') {
|
|
75
70
|
finalCmd = {
|
|
76
71
|
$query: finalCmd,
|
|
77
72
|
$readPreference: readPreference.toJSON()
|
package/lib/db.js
CHANGED
|
@@ -14,7 +14,6 @@ const Logger = require('./core').Logger;
|
|
|
14
14
|
const Collection = require('./collection');
|
|
15
15
|
const mergeOptionsAndWriteConcern = require('./utils').mergeOptionsAndWriteConcern;
|
|
16
16
|
const executeLegacyOperation = require('./utils').executeLegacyOperation;
|
|
17
|
-
const resolveReadPreference = require('./utils').resolveReadPreference;
|
|
18
17
|
const ChangeStream = require('./change_stream');
|
|
19
18
|
const deprecate = require('util').deprecate;
|
|
20
19
|
const deprecateOptions = require('./utils').deprecateOptions;
|
|
@@ -35,6 +34,7 @@ const AggregateOperation = require('./operations/aggregate');
|
|
|
35
34
|
const AddUserOperation = require('./operations/add_user');
|
|
36
35
|
const CollectionsOperation = require('./operations/collections');
|
|
37
36
|
const CommandOperation = require('./operations/command');
|
|
37
|
+
const RunCommandOperation = require('./operations/run_command');
|
|
38
38
|
const CreateCollectionOperation = require('./operations/create_collection');
|
|
39
39
|
const CreateIndexOperation = require('./operations/create_index');
|
|
40
40
|
const DropCollectionOperation = require('./operations/drop').DropCollectionOperation;
|
|
@@ -290,7 +290,7 @@ Db.prototype.command = function(command, options, callback) {
|
|
|
290
290
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
291
291
|
options = Object.assign({}, options);
|
|
292
292
|
|
|
293
|
-
const commandOperation = new
|
|
293
|
+
const commandOperation = new RunCommandOperation(this, command, options);
|
|
294
294
|
|
|
295
295
|
return executeOperation(this.s.topology, commandOperation, callback);
|
|
296
296
|
};
|
|
@@ -709,7 +709,7 @@ Db.prototype.collections = function(options, callback) {
|
|
|
709
709
|
Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
|
|
710
710
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
711
711
|
options = options || {};
|
|
712
|
-
options.readPreference =
|
|
712
|
+
options.readPreference = ReadPreference.resolve(this, options);
|
|
713
713
|
|
|
714
714
|
const executeDbAdminCommandOperation = new ExecuteDbAdminCommandOperation(
|
|
715
715
|
this,
|
|
@@ -8,7 +8,6 @@ const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
|
|
8
8
|
const ensureIndexDb = require('./db_ops').ensureIndex;
|
|
9
9
|
const evaluate = require('./db_ops').evaluate;
|
|
10
10
|
const executeCommand = require('./db_ops').executeCommand;
|
|
11
|
-
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
12
11
|
const handleCallback = require('../utils').handleCallback;
|
|
13
12
|
const indexInformationDb = require('./db_ops').indexInformation;
|
|
14
13
|
const Long = require('../core').BSON.Long;
|
|
@@ -188,7 +187,7 @@ function group(coll, keys, condition, initial, reduce, finalize, command, option
|
|
|
188
187
|
|
|
189
188
|
options = Object.assign({}, options);
|
|
190
189
|
// Ensure we have the right read preference inheritance
|
|
191
|
-
options.readPreference =
|
|
190
|
+
options.readPreference = ReadPreference.resolve(coll, options);
|
|
192
191
|
|
|
193
192
|
// Do we have a readConcern specified
|
|
194
193
|
decorateWithReadConcern(selector, coll, options);
|
|
@@ -7,7 +7,6 @@ const debugOptions = require('../utils').debugOptions;
|
|
|
7
7
|
const handleCallback = require('../utils').handleCallback;
|
|
8
8
|
const MongoError = require('../core').MongoError;
|
|
9
9
|
const ReadPreference = require('../core').ReadPreference;
|
|
10
|
-
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
11
10
|
const MongoDBNamespace = require('../utils').MongoDBNamespace;
|
|
12
11
|
|
|
13
12
|
const debugFields = [
|
|
@@ -38,9 +37,9 @@ class CommandOperation extends OperationBase {
|
|
|
38
37
|
|
|
39
38
|
if (!this.hasAspect(Aspect.WRITE_OPERATION)) {
|
|
40
39
|
if (collection != null) {
|
|
41
|
-
this.options.readPreference =
|
|
40
|
+
this.options.readPreference = ReadPreference.resolve(collection, options);
|
|
42
41
|
} else {
|
|
43
|
-
this.options.readPreference =
|
|
42
|
+
this.options.readPreference = ReadPreference.resolve(db, options);
|
|
44
43
|
}
|
|
45
44
|
} else {
|
|
46
45
|
if (collection != null) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const Aspect = require('./operation').Aspect;
|
|
4
4
|
const OperationBase = require('./operation').OperationBase;
|
|
5
|
-
const
|
|
5
|
+
const ReadPreference = require('../core').ReadPreference;
|
|
6
6
|
const ReadConcern = require('../read_concern');
|
|
7
7
|
const WriteConcern = require('../write_concern');
|
|
8
8
|
const maxWireVersion = require('../core/utils').maxWireVersion;
|
|
@@ -16,9 +16,10 @@ class CommandOperationV2 extends OperationBase {
|
|
|
16
16
|
super(options);
|
|
17
17
|
|
|
18
18
|
this.ns = parent.s.namespace.withCollection('$cmd');
|
|
19
|
-
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
19
|
+
const propertyProvider = this.hasAspect(Aspect.NO_INHERIT_OPTIONS) ? undefined : parent;
|
|
20
|
+
this.readPreference = ReadPreference.resolve(propertyProvider, this.options);
|
|
21
|
+
this.readConcern = resolveReadConcern(propertyProvider, this.options);
|
|
22
|
+
this.writeConcern = resolveWriteConcern(propertyProvider, this.options);
|
|
22
23
|
this.explain = false;
|
|
23
24
|
|
|
24
25
|
if (operationOptions && typeof operationOptions.fullResponse === 'boolean') {
|
|
@@ -97,11 +98,11 @@ class CommandOperationV2 extends OperationBase {
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
function resolveWriteConcern(parent, options) {
|
|
100
|
-
return WriteConcern.fromOptions(options) || parent.writeConcern;
|
|
101
|
+
return WriteConcern.fromOptions(options) || (parent && parent.writeConcern);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
function resolveReadConcern(parent, options) {
|
|
104
|
-
return ReadConcern.fromOptions(options) || parent.readConcern;
|
|
105
|
+
return ReadConcern.fromOptions(options) || (parent && parent.readConcern);
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
module.exports = CommandOperationV2;
|
package/lib/operations/db_ops.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const applyWriteConcern = require('../utils').applyWriteConcern;
|
|
4
4
|
const Code = require('../core').BSON.Code;
|
|
5
|
-
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
6
5
|
const debugOptions = require('../utils').debugOptions;
|
|
7
6
|
const handleCallback = require('../utils').handleCallback;
|
|
8
7
|
const MongoError = require('../core').MongoError;
|
|
@@ -225,7 +224,7 @@ function executeCommand(db, command, options, callback) {
|
|
|
225
224
|
const dbName = options.dbName || options.authdb || db.databaseName;
|
|
226
225
|
|
|
227
226
|
// Convert the readPreference if its not a write
|
|
228
|
-
options.readPreference =
|
|
227
|
+
options.readPreference = ReadPreference.resolve(db, options);
|
|
229
228
|
|
|
230
229
|
// Debug information
|
|
231
230
|
if (db.s.logger.isDebug())
|
package/lib/operations/find.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const OperationBase = require('./operation').OperationBase;
|
|
4
4
|
const Aspect = require('./operation').Aspect;
|
|
5
5
|
const defineAspects = require('./operation').defineAspects;
|
|
6
|
-
const
|
|
6
|
+
const ReadPreference = require('../core').ReadPreference;
|
|
7
7
|
|
|
8
8
|
class FindOperation extends OperationBase {
|
|
9
9
|
constructor(collection, ns, command, options) {
|
|
@@ -11,7 +11,7 @@ class FindOperation extends OperationBase {
|
|
|
11
11
|
|
|
12
12
|
this.ns = ns;
|
|
13
13
|
this.cmd = command;
|
|
14
|
-
this.readPreference =
|
|
14
|
+
this.readPreference = ReadPreference.resolve(collection, this.options);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
execute(server, callback) {
|
|
@@ -7,7 +7,7 @@ const decorateCommand = require('../utils').decorateCommand;
|
|
|
7
7
|
const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
|
8
8
|
const executeCommand = require('./db_ops').executeCommand;
|
|
9
9
|
const handleCallback = require('../utils').handleCallback;
|
|
10
|
-
const
|
|
10
|
+
const ReadPreference = require('../core').ReadPreference;
|
|
11
11
|
const toError = require('../utils').toError;
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -58,7 +58,7 @@ class GeoHaystackSearchOperation extends OperationBase {
|
|
|
58
58
|
|
|
59
59
|
options = Object.assign({}, options);
|
|
60
60
|
// Ensure we have the right read preference inheritance
|
|
61
|
-
options.readPreference =
|
|
61
|
+
options.readPreference = ReadPreference.resolve(coll, options);
|
|
62
62
|
|
|
63
63
|
// Do we have a readConcern specified
|
|
64
64
|
decorateWithReadConcern(commandObject, coll, options);
|
|
@@ -9,7 +9,7 @@ const handleCallback = require('../utils').handleCallback;
|
|
|
9
9
|
const isObject = require('../utils').isObject;
|
|
10
10
|
const loadDb = require('../dynamic_loaders').loadDb;
|
|
11
11
|
const OperationBase = require('./operation').OperationBase;
|
|
12
|
-
const
|
|
12
|
+
const ReadPreference = require('../core').ReadPreference;
|
|
13
13
|
const toError = require('../utils').toError;
|
|
14
14
|
|
|
15
15
|
const exclusionList = [
|
|
@@ -80,7 +80,7 @@ class MapReduceOperation extends OperationBase {
|
|
|
80
80
|
options = Object.assign({}, options);
|
|
81
81
|
|
|
82
82
|
// Ensure we have the right read preference inheritance
|
|
83
|
-
options.readPreference =
|
|
83
|
+
options.readPreference = ReadPreference.resolve(coll, options);
|
|
84
84
|
|
|
85
85
|
// If we have a read preference and inline is not set as output fail hard
|
|
86
86
|
if (
|
|
@@ -4,7 +4,8 @@ const Aspect = {
|
|
|
4
4
|
READ_OPERATION: Symbol('READ_OPERATION'),
|
|
5
5
|
WRITE_OPERATION: Symbol('WRITE_OPERATION'),
|
|
6
6
|
RETRYABLE: Symbol('RETRYABLE'),
|
|
7
|
-
EXECUTE_WITH_SELECTION: Symbol('EXECUTE_WITH_SELECTION')
|
|
7
|
+
EXECUTE_WITH_SELECTION: Symbol('EXECUTE_WITH_SELECTION'),
|
|
8
|
+
NO_INHERIT_OPTIONS: Symbol('NO_INHERIT_OPTIONS')
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const CommandOperationV2 = require('./command_v2');
|
|
4
|
+
const defineAspects = require('./operation').defineAspects;
|
|
5
|
+
const Aspect = require('./operation').Aspect;
|
|
6
|
+
|
|
7
|
+
class RunCommandOperation extends CommandOperationV2 {
|
|
8
|
+
constructor(parent, command, options) {
|
|
9
|
+
super(parent, options);
|
|
10
|
+
this.command = command;
|
|
11
|
+
}
|
|
12
|
+
execute(server, callback) {
|
|
13
|
+
const command = this.command;
|
|
14
|
+
this.executeCommand(server, command, callback);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
defineAspects(RunCommandOperation, [Aspect.EXECUTE_WITH_SELECTION, Aspect.NO_INHERIT_OPTIONS]);
|
|
18
|
+
|
|
19
|
+
module.exports = RunCommandOperation;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const EventEmitter = require('events'),
|
|
4
4
|
MongoError = require('../core').MongoError,
|
|
5
5
|
f = require('util').format,
|
|
6
|
-
|
|
6
|
+
ReadPreference = require('../core').ReadPreference,
|
|
7
7
|
ClientSession = require('../core').Sessions.ClientSession;
|
|
8
8
|
|
|
9
9
|
// The store of ops
|
|
@@ -293,7 +293,7 @@ class TopologyBase extends EventEmitter {
|
|
|
293
293
|
|
|
294
294
|
// Command
|
|
295
295
|
command(ns, cmd, options, callback) {
|
|
296
|
-
this.s.coreTopology.command(ns.toString(), cmd,
|
|
296
|
+
this.s.coreTopology.command(ns.toString(), cmd, ReadPreference.translate(options), callback);
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
// Insert
|
|
@@ -314,7 +314,7 @@ class TopologyBase extends EventEmitter {
|
|
|
314
314
|
// IsConnected
|
|
315
315
|
isConnected(options) {
|
|
316
316
|
options = options || {};
|
|
317
|
-
options =
|
|
317
|
+
options = ReadPreference.translate(options);
|
|
318
318
|
|
|
319
319
|
return this.s.coreTopology.isConnected(options);
|
|
320
320
|
}
|
|
@@ -327,7 +327,7 @@ class TopologyBase extends EventEmitter {
|
|
|
327
327
|
// Cursor
|
|
328
328
|
cursor(ns, cmd, options) {
|
|
329
329
|
options = options || {};
|
|
330
|
-
options =
|
|
330
|
+
options = ReadPreference.translate(options);
|
|
331
331
|
options.disconnectHandler = this.s.store;
|
|
332
332
|
options.topology = this;
|
|
333
333
|
|
package/lib/utils.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const MongoError = require('./core/error').MongoError;
|
|
3
|
-
const ReadPreference = require('./core/topologies/read_preference');
|
|
4
3
|
const WriteConcern = require('./write_concern');
|
|
5
4
|
|
|
6
5
|
var shallowClone = function(obj) {
|
|
@@ -9,31 +8,6 @@ var shallowClone = function(obj) {
|
|
|
9
8
|
return copy;
|
|
10
9
|
};
|
|
11
10
|
|
|
12
|
-
// Figure out the read preference
|
|
13
|
-
var translateReadPreference = function(options) {
|
|
14
|
-
var r = null;
|
|
15
|
-
if (options.readPreference) {
|
|
16
|
-
r = options.readPreference;
|
|
17
|
-
} else {
|
|
18
|
-
return options;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (typeof r === 'string') {
|
|
22
|
-
options.readPreference = new ReadPreference(r);
|
|
23
|
-
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
|
24
|
-
const mode = r.mode || r.preference;
|
|
25
|
-
if (mode && typeof mode === 'string') {
|
|
26
|
-
options.readPreference = new ReadPreference(mode, r.tags, {
|
|
27
|
-
maxStalenessSeconds: r.maxStalenessSeconds
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
} else if (!(r instanceof ReadPreference)) {
|
|
31
|
-
throw new TypeError('Invalid read preference: ' + r);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return options;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
11
|
// Set simple property
|
|
38
12
|
var getSingleProperty = function(obj, name, value) {
|
|
39
13
|
Object.defineProperty(obj, name, {
|
|
@@ -490,37 +464,6 @@ function applyWriteConcern(target, sources, options) {
|
|
|
490
464
|
return target;
|
|
491
465
|
}
|
|
492
466
|
|
|
493
|
-
/**
|
|
494
|
-
* Resolves a read preference based on well-defined inheritance rules. This method will not only
|
|
495
|
-
* determine the read preference (if there is one), but will also ensure the returned value is a
|
|
496
|
-
* properly constructed instance of `ReadPreference`.
|
|
497
|
-
*
|
|
498
|
-
* @param {Collection|Db|MongoClient} parent The parent of the operation on which to determine the read
|
|
499
|
-
* preference, used for determining the inherited read preference.
|
|
500
|
-
* @param {Object} options The options passed into the method, potentially containing a read preference
|
|
501
|
-
* @returns {(ReadPreference|null)} The resolved read preference
|
|
502
|
-
*/
|
|
503
|
-
function resolveReadPreference(parent, options) {
|
|
504
|
-
options = options || {};
|
|
505
|
-
const session = options.session;
|
|
506
|
-
|
|
507
|
-
const inheritedReadPreference = parent.readPreference;
|
|
508
|
-
|
|
509
|
-
let readPreference;
|
|
510
|
-
if (options.readPreference) {
|
|
511
|
-
readPreference = ReadPreference.fromOptions(options);
|
|
512
|
-
} else if (session && session.inTransaction() && session.transaction.options.readPreference) {
|
|
513
|
-
// The transaction’s read preference MUST override all other user configurable read preferences.
|
|
514
|
-
readPreference = session.transaction.options.readPreference;
|
|
515
|
-
} else if (inheritedReadPreference != null) {
|
|
516
|
-
readPreference = inheritedReadPreference;
|
|
517
|
-
} else {
|
|
518
|
-
throw new Error('No readPreference was provided or inherited.');
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return typeof readPreference === 'string' ? new ReadPreference(readPreference) : readPreference;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
467
|
/**
|
|
525
468
|
* Checks if a given value is a Promise
|
|
526
469
|
*
|
|
@@ -843,7 +786,6 @@ module.exports = {
|
|
|
843
786
|
debugOptions,
|
|
844
787
|
MAX_JS_INT: Number.MAX_SAFE_INTEGER + 1,
|
|
845
788
|
mergeOptionsAndWriteConcern,
|
|
846
|
-
translateReadPreference,
|
|
847
789
|
executeLegacyOperation,
|
|
848
790
|
applyRetryableWrites,
|
|
849
791
|
applyWriteConcern,
|
|
@@ -853,7 +795,6 @@ module.exports = {
|
|
|
853
795
|
deprecateOptions,
|
|
854
796
|
SUPPORTS,
|
|
855
797
|
MongoDBNamespace,
|
|
856
|
-
resolveReadPreference,
|
|
857
798
|
emitDeprecationWarning,
|
|
858
799
|
makeCounter,
|
|
859
800
|
maybePromise,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongodb",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.10",
|
|
4
4
|
"description": "The official MongoDB driver for Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"url": "https://github.com/mongodb/node-mongodb-native/issues"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
|
-
"atlas": "
|
|
67
|
+
"atlas": "mocha --opts '{}' ./test/manual/atlas_connectivity.test.js",
|
|
68
68
|
"test": "npm run lint && mocha --recursive test/functional test/unit test/core",
|
|
69
69
|
"test-nolint": "mocha --recursive test/functional test/unit test/core",
|
|
70
70
|
"coverage": "istanbul cover mongodb-test-runner -- -t 60000 test/core test/unit test/functional",
|