mongodb 3.6.6 → 3.6.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.
Files changed (42) hide show
  1. package/HISTORY.md +39 -0
  2. package/README.md +4 -4
  3. package/lib/bulk/common.js +96 -1
  4. package/lib/cmap/connection.js +37 -32
  5. package/lib/collection.js +56 -32
  6. package/lib/command_utils.js +124 -0
  7. package/lib/core/auth/mongo_credentials.js +5 -5
  8. package/lib/core/connection/apm.js +10 -123
  9. package/lib/core/connection/commands.js +11 -2
  10. package/lib/core/connection/connect.js +3 -0
  11. package/lib/core/connection/connection.js +6 -3
  12. package/lib/core/connection/msg.js +11 -2
  13. package/lib/core/connection/pool.js +6 -2
  14. package/lib/core/cursor.js +7 -0
  15. package/lib/core/error.js +2 -2
  16. package/lib/core/sdam/monitor.js +2 -1
  17. package/lib/core/sdam/server.js +8 -1
  18. package/lib/core/sdam/topology.js +24 -15
  19. package/lib/core/topologies/mongos.js +1 -0
  20. package/lib/core/topologies/replset.js +2 -1
  21. package/lib/core/topologies/server.js +7 -2
  22. package/lib/core/uri_parser.js +3 -1
  23. package/lib/core/wireprotocol/command.js +10 -5
  24. package/lib/core/wireprotocol/constants.js +2 -2
  25. package/lib/core/wireprotocol/shared.js +1 -0
  26. package/lib/cursor.js +12 -2
  27. package/lib/db.js +82 -72
  28. package/lib/mongo_client.js +89 -164
  29. package/lib/operations/bulk_write.js +0 -25
  30. package/lib/operations/command.js +4 -1
  31. package/lib/operations/command_v2.js +7 -1
  32. package/lib/operations/connect.js +2 -1
  33. package/lib/operations/db_ops.js +6 -2
  34. package/lib/operations/find_one_and_replace.js +8 -2
  35. package/lib/operations/find_one_and_update.js +8 -3
  36. package/lib/operations/insert_many.js +1 -5
  37. package/lib/topologies/mongos.js +1 -0
  38. package/lib/topologies/replset.js +1 -0
  39. package/lib/topologies/server.js +1 -0
  40. package/lib/url_parser.js +2 -1
  41. package/lib/utils.js +90 -6
  42. package/package.json +22 -15
package/HISTORY.md CHANGED
@@ -2,6 +2,45 @@
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.6.10](https://github.com/mongodb/node-mongodb-native/compare/v3.6.9...v3.6.10) (2021-07-06)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **NODE-2035:** Exceptions thrown from awaited cursor forEach do not propagate ([#2852](https://github.com/mongodb/node-mongodb-native/issues/2852)) ([a917dfa](https://github.com/mongodb/node-mongodb-native/commit/a917dfada67859412344ed238796cf3bee243f5f))
11
+ * **NODE-3150:** added bsonRegExp option for v3.6 ([#2843](https://github.com/mongodb/node-mongodb-native/issues/2843)) ([e4a9a57](https://github.com/mongodb/node-mongodb-native/commit/e4a9a572427666fd1a89576dadf50b9c452e1659))
12
+ * **NODE-3358:** Command monitoring objects hold internal state references ([#2858](https://github.com/mongodb/node-mongodb-native/issues/2858)) ([750760c](https://github.com/mongodb/node-mongodb-native/commit/750760c324ddedb72491befde9f7aff1ceec009c))
13
+ * **NODE-3380:** perform retryable write checks against server ([#2861](https://github.com/mongodb/node-mongodb-native/issues/2861)) ([621677a](https://github.com/mongodb/node-mongodb-native/commit/621677a42772e0b26aa13883f57d7e42f86df43f))
14
+ * **NODE-3397:** report more helpful error with unsupported authMechanism in initial handshake ([#2876](https://github.com/mongodb/node-mongodb-native/issues/2876)) ([3ce148d](https://github.com/mongodb/node-mongodb-native/commit/3ce148d8fb37faea1ee056f6e9331e5282e65cd0))
15
+
16
+ ### [3.6.9](https://github.com/mongodb/node-mongodb-native/compare/v3.6.8...v3.6.9) (2021-05-26)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * **NODE-3309:** remove redundant iteration of bulk write result ([#2815](https://github.com/mongodb/node-mongodb-native/issues/2815)) ([fac9610](https://github.com/mongodb/node-mongodb-native/commit/fac961086eafa0f7437576fd6af900e1f9fe22ed))
22
+ * fix url parsing for a mongodb+srv url that has commas in the database name ([#2789](https://github.com/mongodb/node-mongodb-native/issues/2789)) ([58c4e69](https://github.com/mongodb/node-mongodb-native/commit/58c4e693cc3a717254144d5f9bdddd8414217e97))
23
+
24
+ ### [3.6.8](https://github.com/mongodb/node-mongodb-native/compare/v3.6.7...v3.6.8) (2021-05-21)
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * **cmap:** undo flipping of `beforeHandshake` flag for timeout errors ([#2813](https://github.com/mongodb/node-mongodb-native/issues/2813)) ([6e3bab3](https://github.com/mongodb/node-mongodb-native/commit/6e3bab32204ea905ab9b949edccb68556b50d382))
30
+
31
+ ### [3.6.7](https://github.com/mongodb/node-mongodb-native/compare/v3.6.6...v3.6.7) (2021-05-18)
32
+
33
+
34
+ ### Bug Fixes
35
+
36
+ * **docs:** removing incorrect apm docs ([#2793](https://github.com/mongodb/node-mongodb-native/issues/2793)) ([971259a](https://github.com/mongodb/node-mongodb-native/commit/971259a868a8018e90ebc2f28d151eb7af3dd50a))
37
+ * **NODE-3173:** Preserve sort key order for numeric string keys ([#2790](https://github.com/mongodb/node-mongodb-native/issues/2790)) ([730f43a](https://github.com/mongodb/node-mongodb-native/commit/730f43af6d9e53603af998353b720d8161426d8c))
38
+ * **NODE-3176:** handle errors from MessageStream ([#2774](https://github.com/mongodb/node-mongodb-native/issues/2774)) ([f1afcc4](https://github.com/mongodb/node-mongodb-native/commit/f1afcc4efbc41ce436812a6bfa22843e939ab5cf))
39
+ * **NODE-3192:** check clusterTime is defined before access ([#2806](https://github.com/mongodb/node-mongodb-native/issues/2806)) ([6ceace6](https://github.com/mongodb/node-mongodb-native/commit/6ceace6b245c42b8498fb1b13e7c37a97a46946d))
40
+ * **NODE-3252:** state transistion from DISCONNECTED ([#2807](https://github.com/mongodb/node-mongodb-native/issues/2807)) ([5d8f649](https://github.com/mongodb/node-mongodb-native/commit/5d8f6493a0ba4b525434c0868e2ae12315b4c249))
41
+ * **sdam:** topology no longer causes close event ([#2791](https://github.com/mongodb/node-mongodb-native/issues/2791)) ([16e7064](https://github.com/mongodb/node-mongodb-native/commit/16e70642f25954a03b91a2c2991cea96b8356de7))
42
+ * invalid case on writeconcern makes skip check fail ([#2773](https://github.com/mongodb/node-mongodb-native/issues/2773)) ([b1363c2](https://github.com/mongodb/node-mongodb-native/commit/b1363c26db5da5003f9db43be7e8d6e9007d45bd))
43
+
5
44
  ### [3.6.6](https://github.com/mongodb/node-mongodb-native/compare/v3.6.5...v3.6.6) (2021-04-06)
6
45
 
7
46
 
package/README.md CHANGED
@@ -15,10 +15,10 @@ Check out our [beta version 4.0 here](https://github.com/mongodb/node-mongodb-na
15
15
 
16
16
  | what | where |
17
17
  | ------------- | ---------------------------------------------------- |
18
- | documentation | http://mongodb.github.io/node-mongodb-native |
19
- | api-doc | http://mongodb.github.io/node-mongodb-native/3.6/api |
18
+ | documentation | https://mongodb.github.io/node-mongodb-native |
19
+ | api-doc | https://mongodb.github.io/node-mongodb-native/3.6/api |
20
20
  | source | https://github.com/mongodb/node-mongodb-native |
21
- | mongodb | http://www.mongodb.org |
21
+ | mongodb | https://www.mongodb.org |
22
22
 
23
23
  ### Bugs / Feature Requests
24
24
 
@@ -481,7 +481,7 @@ For more detailed information, see the [tutorials](docs/reference/content/tutori
481
481
 
482
482
  ## Next Steps
483
483
 
484
- - [MongoDB Documentation](http://mongodb.org)
484
+ - [MongoDB Documentation](https://mongodb.org)
485
485
  - [Read about Schemas](http://learnmongodbthehardway.com)
486
486
  - [Star us on GitHub](https://github.com/mongodb/node-mongodb-native)
487
487
 
@@ -5,6 +5,7 @@ const MongoError = require('../core').MongoError;
5
5
  const ObjectID = require('../core').BSON.ObjectID;
6
6
  const BSON = require('../core').BSON;
7
7
  const MongoWriteConcernError = require('../core').MongoWriteConcernError;
8
+ const emitWarningOnce = require('../utils').emitWarningOnce;
8
9
  const toError = require('../utils').toError;
9
10
  const handleCallback = require('../utils').handleCallback;
10
11
  const applyRetryableWrites = require('../utils').applyRetryableWrites;
@@ -56,6 +57,9 @@ class Batch {
56
57
  }
57
58
  }
58
59
 
60
+ const kUpsertedIds = Symbol('upsertedIds');
61
+ const kInsertedIds = Symbol('insertedIds');
62
+
59
63
  /**
60
64
  * @classdesc
61
65
  * The result of a bulk write.
@@ -68,6 +72,60 @@ class BulkWriteResult {
68
72
  */
69
73
  constructor(bulkResult) {
70
74
  this.result = bulkResult;
75
+ this[kUpsertedIds] = undefined;
76
+ this[kInsertedIds] = undefined;
77
+ }
78
+
79
+ /** Number of documents inserted. */
80
+ get insertedCount() {
81
+ return typeof this.result.nInserted !== 'number' ? 0 : this.result.nInserted;
82
+ }
83
+ /** Number of documents matched for update. */
84
+ get matchedCount() {
85
+ return typeof this.result.nMatched !== 'number' ? 0 : this.result.nMatched;
86
+ }
87
+ /** Number of documents modified. */
88
+ get modifiedCount() {
89
+ return typeof this.result.nModified !== 'number' ? 0 : this.result.nModified;
90
+ }
91
+ /** Number of documents deleted. */
92
+ get deletedCount() {
93
+ return typeof this.result.nRemoved !== 'number' ? 0 : this.result.nRemoved;
94
+ }
95
+ /** Number of documents upserted. */
96
+ get upsertedCount() {
97
+ return !this.result.upserted ? 0 : this.result.upserted.length;
98
+ }
99
+
100
+ /** Upserted document generated Id's, hash key is the index of the originating operation */
101
+ get upsertedIds() {
102
+ if (this[kUpsertedIds]) {
103
+ return this[kUpsertedIds];
104
+ }
105
+
106
+ this[kUpsertedIds] = {};
107
+ for (const doc of this.result.upserted || []) {
108
+ this[kUpsertedIds][doc.index] = doc._id;
109
+ }
110
+ return this[kUpsertedIds];
111
+ }
112
+
113
+ /** Inserted document generated Id's, hash key is the index of the originating operation */
114
+ get insertedIds() {
115
+ if (this[kInsertedIds]) {
116
+ return this[kInsertedIds];
117
+ }
118
+
119
+ this[kInsertedIds] = {};
120
+ for (const doc of this.result.insertedIds || []) {
121
+ this[kInsertedIds][doc.index] = doc._id;
122
+ }
123
+ return this[kInsertedIds];
124
+ }
125
+
126
+ /** The number of inserted documents @type {number} */
127
+ get n() {
128
+ return this.result.insertedCount;
71
129
  }
72
130
 
73
131
  /**
@@ -571,6 +629,35 @@ class BulkWriteError extends MongoError {
571
629
  this.name = 'BulkWriteError';
572
630
  this.result = result;
573
631
  }
632
+
633
+ /** Number of documents inserted. */
634
+ get insertedCount() {
635
+ return this.result.insertedCount;
636
+ }
637
+ /** Number of documents matched for update. */
638
+ get matchedCount() {
639
+ return this.result.matchedCount;
640
+ }
641
+ /** Number of documents modified. */
642
+ get modifiedCount() {
643
+ return this.result.modifiedCount;
644
+ }
645
+ /** Number of documents deleted. */
646
+ get deletedCount() {
647
+ return this.result.deletedCount;
648
+ }
649
+ /** Number of documents upserted. */
650
+ get upsertedCount() {
651
+ return this.result.upsertedCount;
652
+ }
653
+ /** Inserted document generated Id's, hash key is the index of the originating operation */
654
+ get insertedIds() {
655
+ return this.result.insertedIds;
656
+ }
657
+ /** Upserted document generated Id's, hash key is the index of the originating operation */
658
+ get upsertedIds() {
659
+ return this.result.upsertedIds;
660
+ }
574
661
  }
575
662
 
576
663
  /**
@@ -737,15 +824,19 @@ class FindOperators {
737
824
 
738
825
  /**
739
826
  * backwards compatability for deleteOne
827
+ * @deprecated
740
828
  */
741
829
  removeOne() {
830
+ emitWarningOnce('bulk operation `removeOne` has been deprecated, please use `deleteOne`');
742
831
  return this.deleteOne();
743
832
  }
744
833
 
745
834
  /**
746
835
  * backwards compatability for delete
836
+ * @deprecated
747
837
  */
748
838
  remove() {
839
+ emitWarningOnce('bulk operation `remove` has been deprecated, please use `delete`');
749
840
  return this.delete();
750
841
  }
751
842
  }
@@ -1041,6 +1132,9 @@ class BulkOperationBase {
1041
1132
  }
1042
1133
 
1043
1134
  if (op.insertMany) {
1135
+ emitWarningOnce(
1136
+ 'bulk operation `insertMany` has been deprecated; use multiple `insertOne` ops instead'
1137
+ );
1044
1138
  for (let i = 0; i < op.insertMany.length; i++) {
1045
1139
  if (forceServerObjectId !== true && op.insertMany[i]._id == null)
1046
1140
  op.insertMany[i]._id = new ObjectID();
@@ -1294,5 +1388,6 @@ module.exports = {
1294
1388
  INSERT: INSERT,
1295
1389
  UPDATE: UPDATE,
1296
1390
  REMOVE: REMOVE,
1297
- BulkWriteError
1391
+ BulkWriteError,
1392
+ BulkWriteResult
1298
1393
  };
@@ -58,38 +58,9 @@ class Connection extends EventEmitter {
58
58
  /* ignore errors, listen to `close` instead */
59
59
  });
60
60
 
61
- stream.on('close', () => {
62
- if (this.closed) {
63
- return;
64
- }
65
-
66
- this.closed = true;
67
- this[kQueue].forEach(op =>
68
- op.cb(new MongoNetworkError(`connection ${this.id} to ${this.address} closed`))
69
- );
70
- this[kQueue].clear();
71
-
72
- this.emit('close');
73
- });
74
-
75
- stream.on('timeout', () => {
76
- if (this.closed) {
77
- return;
78
- }
79
-
80
- stream.destroy();
81
- this.closed = true;
82
- this[kQueue].forEach(op =>
83
- op.cb(
84
- new MongoNetworkTimeoutError(`connection ${this.id} to ${this.address} timed out`, {
85
- beforeHandshake: this[kIsMaster] == null
86
- })
87
- )
88
- );
89
-
90
- this[kQueue].clear();
91
- this.emit('close');
92
- });
61
+ this[kMessageStream].on('error', error => this.handleIssue({ destroy: error }));
62
+ stream.on('close', () => this.handleIssue({ isClose: true }));
63
+ stream.on('timeout', () => this.handleIssue({ isTimeout: true, destroy: true }));
93
64
 
94
65
  // hook the message stream up to the passed in stream
95
66
  stream.pipe(this[kMessageStream]);
@@ -132,6 +103,39 @@ class Connection extends EventEmitter {
132
103
  this[kLastUseTime] = now();
133
104
  }
134
105
 
106
+ /**
107
+ * @param {{ isTimeout?: boolean; isClose?: boolean; destroy?: boolean | Error }} issue
108
+ */
109
+ handleIssue(issue) {
110
+ if (this.closed) {
111
+ return;
112
+ }
113
+
114
+ if (issue.destroy) {
115
+ this[kStream].destroy(typeof issue.destroy === 'boolean' ? undefined : issue.destroy);
116
+ }
117
+
118
+ this.closed = true;
119
+
120
+ for (const idAndOp of this[kQueue]) {
121
+ const op = idAndOp[1];
122
+ if (issue.isTimeout) {
123
+ op.cb(
124
+ new MongoNetworkTimeoutError(`connection ${this.id} to ${this.address} timed out`, {
125
+ beforeHandshake: this.ismaster == null
126
+ })
127
+ );
128
+ } else if (issue.isClose) {
129
+ op.cb(new MongoNetworkError(`connection ${this.id} to ${this.address} closed`));
130
+ } else {
131
+ op.cb(typeof issue.destroy === 'boolean' ? undefined : issue.destroy);
132
+ }
133
+ }
134
+
135
+ this[kQueue].clear();
136
+ this.emit('close');
137
+ }
138
+
135
139
  destroy(options, callback) {
136
140
  if (typeof options === 'function') {
137
141
  callback = options;
@@ -313,6 +317,7 @@ function write(command, options, callback) {
313
317
  promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
314
318
  promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
315
319
  promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
320
+ bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false,
316
321
  raw: typeof options.raw === 'boolean' ? options.raw : false
317
322
  };
318
323
 
package/lib/collection.js CHANGED
@@ -120,6 +120,8 @@ function Collection(db, topology, dbName, name, pkFactory, options) {
120
120
  options == null || options.promoteBuffers == null
121
121
  ? db.s.options.promoteBuffers
122
122
  : options.promoteBuffers;
123
+ const bsonRegExp =
124
+ options == null || options.bsonRegExp == null ? db.s.options.bsonRegExp : options.bsonRegExp;
123
125
  const collectionHint = null;
124
126
 
125
127
  const namespace = new MongoDBNamespace(dbName, name);
@@ -156,6 +158,8 @@ function Collection(db, topology, dbName, name, pkFactory, options) {
156
158
  promoteValues: promoteValues,
157
159
  // promoteBuffers
158
160
  promoteBuffers: promoteBuffers,
161
+ // bsonRegExp
162
+ bsonRegExp: bsonRegExp,
159
163
  // internalHint
160
164
  internalHint: internalHint,
161
165
  // collectionHint
@@ -303,6 +307,7 @@ const DEPRECATED_FIND_OPTIONS = ['maxScan', 'fields', 'snapshot', 'oplogReplay']
303
307
  * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
304
308
  * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
305
309
  * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
310
+ * @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
306
311
  * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
307
312
  * @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
308
313
  * @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
@@ -451,6 +456,8 @@ Collection.prototype.find = deprecateOptions(
451
456
  newOptions.promoteValues = this.s.promoteValues;
452
457
  if (newOptions.promoteBuffers == null && typeof this.s.promoteBuffers === 'boolean')
453
458
  newOptions.promoteBuffers = this.s.promoteBuffers;
459
+ if (newOptions.bsonRegExp == null && typeof this.s.bsonRegExp === 'boolean')
460
+ newOptions.bsonRegExp = this.s.bsonRegExp;
454
461
 
455
462
  // Sort options
456
463
  if (findCommand.sort) {
@@ -1075,6 +1082,7 @@ Collection.prototype.save = deprecate(function(doc, options, callback) {
1075
1082
  * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
1076
1083
  * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
1077
1084
  * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
1085
+ * @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
1078
1086
  * @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
1079
1087
  * @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
1080
1088
  * @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
@@ -1655,7 +1663,7 @@ Collection.prototype.stats = function(options, callback) {
1655
1663
 
1656
1664
  /**
1657
1665
  * @typedef {Object} Collection~findAndModifyWriteOpResult
1658
- * @property {object} value Document returned from the `findAndModify` command. If no documents were found, `value` will be `null` by default (`returnOriginal: true`), even if a document was upserted; if `returnOriginal` was false, the upserted document will be returned in that case.
1666
+ * @property {object} value Document returned from the `findAndModify` command. If no documents were found, `value` will be `null` by default even if a document was upserted unless `returnDocument` is specified as `'after'`, in which case the upserted document will be returned.
1659
1667
  * @property {object} lastErrorObject The raw lastErrorObject returned from the command. See {@link https://docs.mongodb.com/manual/reference/command/findAndModify/index.html#lasterrorobject|findAndModify command documentation}.
1660
1668
  * @property {Number} ok Is 1 if the command executed correctly.
1661
1669
  */
@@ -1716,7 +1724,8 @@ Collection.prototype.findOneAndDelete = function(filter, options, callback) {
1716
1724
  * @param {object} [options.projection] Limits the fields to return for all matching documents.
1717
1725
  * @param {object} [options.sort] Determines which document the operation modifies if the query selects multiple documents.
1718
1726
  * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
1719
- * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
1727
+ * @param {'before'|'after'} [options.returnDocument='before'] When set to `'after'`, returns the updated document rather than the original. The default is `'before'`.
1728
+ * @param {boolean} [options.returnOriginal=true] **Deprecated** Use `options.returnDocument` instead.
1720
1729
  * @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
1721
1730
  * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
1722
1731
  * @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
@@ -1725,22 +1734,29 @@ Collection.prototype.findOneAndDelete = function(filter, options, callback) {
1725
1734
  * @param {Collection~findAndModifyCallback} [callback] The collection result callback
1726
1735
  * @return {Promise<Collection~findAndModifyWriteOpResultObject>} returns Promise if no callback passed
1727
1736
  */
1728
- Collection.prototype.findOneAndReplace = function(filter, replacement, options, callback) {
1729
- if (typeof options === 'function') (callback = options), (options = {});
1730
- options = options || {};
1737
+ Collection.prototype.findOneAndReplace = deprecateOptions(
1738
+ {
1739
+ name: 'collection.findOneAndReplace',
1740
+ deprecatedOptions: ['returnOriginal'],
1741
+ optionsIndex: 2
1742
+ },
1743
+ function(filter, replacement, options, callback) {
1744
+ if (typeof options === 'function') (callback = options), (options = {});
1745
+ options = options || {};
1731
1746
 
1732
- // Add ignoreUndefined
1733
- if (this.s.options.ignoreUndefined) {
1734
- options = Object.assign({}, options);
1735
- options.ignoreUndefined = this.s.options.ignoreUndefined;
1736
- }
1747
+ // Add ignoreUndefined
1748
+ if (this.s.options.ignoreUndefined) {
1749
+ options = Object.assign({}, options);
1750
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
1751
+ }
1737
1752
 
1738
- return executeOperation(
1739
- this.s.topology,
1740
- new FindOneAndReplaceOperation(this, filter, replacement, options),
1741
- callback
1742
- );
1743
- };
1753
+ return executeOperation(
1754
+ this.s.topology,
1755
+ new FindOneAndReplaceOperation(this, filter, replacement, options),
1756
+ callback
1757
+ );
1758
+ }
1759
+ );
1744
1760
 
1745
1761
  /**
1746
1762
  * Find a document and update it in one atomic operation. Requires a write lock for the duration of the operation.
@@ -1757,7 +1773,8 @@ Collection.prototype.findOneAndReplace = function(filter, replacement, options,
1757
1773
  * @param {object} [options.projection] Limits the fields to return for all matching documents.
1758
1774
  * @param {object} [options.sort] Determines which document the operation modifies if the query selects multiple documents.
1759
1775
  * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
1760
- * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
1776
+ * @param {'before'|'after'} [options.returnDocument='before'] When set to `'after'`, returns the updated document rather than the original. The default is `'before'`.
1777
+ * @param {boolean} [options.returnOriginal=true] **Deprecated** Use `options.returnDocument` instead.
1761
1778
  * @param {boolean} [options.checkKeys=false] If true, will throw if bson documents start with `$` or include a `.` in any key value
1762
1779
  * @param {boolean} [options.serializeFunctions=false] Serialize functions on any object.
1763
1780
  * @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
@@ -1766,22 +1783,29 @@ Collection.prototype.findOneAndReplace = function(filter, replacement, options,
1766
1783
  * @param {Collection~findAndModifyCallback} [callback] The collection result callback
1767
1784
  * @return {Promise<Collection~findAndModifyWriteOpResultObject>} returns Promise if no callback passed
1768
1785
  */
1769
- Collection.prototype.findOneAndUpdate = function(filter, update, options, callback) {
1770
- if (typeof options === 'function') (callback = options), (options = {});
1771
- options = options || {};
1786
+ Collection.prototype.findOneAndUpdate = deprecateOptions(
1787
+ {
1788
+ name: 'collection.findOneAndUpdate',
1789
+ deprecatedOptions: ['returnOriginal'],
1790
+ optionsIndex: 2
1791
+ },
1792
+ function(filter, update, options, callback) {
1793
+ if (typeof options === 'function') (callback = options), (options = {});
1794
+ options = options || {};
1772
1795
 
1773
- // Add ignoreUndefined
1774
- if (this.s.options.ignoreUndefined) {
1775
- options = Object.assign({}, options);
1776
- options.ignoreUndefined = this.s.options.ignoreUndefined;
1777
- }
1796
+ // Add ignoreUndefined
1797
+ if (this.s.options.ignoreUndefined) {
1798
+ options = Object.assign({}, options);
1799
+ options.ignoreUndefined = this.s.options.ignoreUndefined;
1800
+ }
1778
1801
 
1779
- return executeOperation(
1780
- this.s.topology,
1781
- new FindOneAndUpdateOperation(this, filter, update, options),
1782
- callback
1783
- );
1784
- };
1802
+ return executeOperation(
1803
+ this.s.topology,
1804
+ new FindOneAndUpdateOperation(this, filter, update, options),
1805
+ callback
1806
+ );
1807
+ }
1808
+ );
1785
1809
 
1786
1810
  /**
1787
1811
  * Find and update a document.
@@ -1883,6 +1907,7 @@ Collection.prototype.findAndRemove = deprecate(function(query, sort, options, ca
1883
1907
  * @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
1884
1908
  * @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
1885
1909
  * @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
1910
+ * @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
1886
1911
  * @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
1887
1912
  * @param {string} [options.comment] Add a comment to an aggregation command
1888
1913
  * @param {string|object} [options.hint] Add an index selection hint to an aggregation command
@@ -2199,7 +2224,6 @@ Collection.prototype.initializeUnorderedBulkOp = function(options) {
2199
2224
  * @param {object|WriteConcern} [options.writeConcern] Specify write concern settings.
2200
2225
  * @param {ClientSession} [options.session] optional session to use for this operation
2201
2226
  * @param {boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
2202
- * @param {OrderedBulkOperation} callback The command result callback
2203
2227
  * @return {null}
2204
2228
  */
2205
2229
  Collection.prototype.initializeOrderedBulkOp = function(options) {
@@ -0,0 +1,124 @@
1
+ 'use strict';
2
+ const Msg = require('./core/connection/msg').Msg;
3
+ const KillCursor = require('./core/connection/commands').KillCursor;
4
+ const GetMore = require('./core/connection/commands').GetMore;
5
+ const deepCopy = require('./utils').deepCopy;
6
+
7
+ /** Commands that we want to redact because of the sensitive nature of their contents */
8
+ const SENSITIVE_COMMANDS = new Set([
9
+ 'authenticate',
10
+ 'saslStart',
11
+ 'saslContinue',
12
+ 'getnonce',
13
+ 'createUser',
14
+ 'updateUser',
15
+ 'copydbgetnonce',
16
+ 'copydbsaslstart',
17
+ 'copydb'
18
+ ]);
19
+
20
+ const HELLO_COMMANDS = new Set(['hello', 'ismaster', 'isMaster']);
21
+
22
+ const LEGACY_FIND_QUERY_MAP = {
23
+ $query: 'filter',
24
+ $orderby: 'sort',
25
+ $hint: 'hint',
26
+ $comment: 'comment',
27
+ $maxScan: 'maxScan',
28
+ $max: 'max',
29
+ $min: 'min',
30
+ $returnKey: 'returnKey',
31
+ $showDiskLoc: 'showRecordId',
32
+ $maxTimeMS: 'maxTimeMS',
33
+ $snapshot: 'snapshot'
34
+ };
35
+
36
+ const LEGACY_FIND_OPTIONS_MAP = {
37
+ numberToSkip: 'skip',
38
+ numberToReturn: 'batchSize',
39
+ returnFieldsSelector: 'projection'
40
+ };
41
+
42
+ const OP_QUERY_KEYS = [
43
+ 'tailable',
44
+ 'oplogReplay',
45
+ 'noCursorTimeout',
46
+ 'awaitData',
47
+ 'partial',
48
+ 'exhaust'
49
+ ];
50
+
51
+ const collectionName = command => command.ns.split('.')[1];
52
+
53
+ const shouldRedactCommand = (commandName, cmd) =>
54
+ SENSITIVE_COMMANDS.has(commandName) ||
55
+ (HELLO_COMMANDS.has(commandName) && !!cmd.speculativeAuthenticate);
56
+
57
+ /**
58
+ * Extract the actual command from the query, possibly upconverting if it's a legacy
59
+ * format
60
+ *
61
+ * @param {Object} command the command
62
+ */
63
+ const extractCommand = command => {
64
+ let extractedCommand;
65
+ if (command instanceof GetMore) {
66
+ extractedCommand = {
67
+ getMore: deepCopy(command.cursorId),
68
+ collection: collectionName(command),
69
+ batchSize: command.numberToReturn
70
+ };
71
+ } else if (command instanceof KillCursor) {
72
+ extractedCommand = {
73
+ killCursors: collectionName(command),
74
+ cursors: deepCopy(command.cursorIds)
75
+ };
76
+ } else if (command instanceof Msg) {
77
+ extractedCommand = deepCopy(command.command);
78
+ } else if (command.query && command.query.$query) {
79
+ let result;
80
+ if (command.ns === 'admin.$cmd') {
81
+ // upconvert legacy command
82
+ result = Object.assign({}, command.query.$query);
83
+ } else {
84
+ // upconvert legacy find command
85
+ result = { find: collectionName(command) };
86
+ Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
87
+ if (typeof command.query[key] !== 'undefined')
88
+ result[LEGACY_FIND_QUERY_MAP[key]] = deepCopy(command.query[key]);
89
+ });
90
+ }
91
+
92
+ Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
93
+ if (typeof command[key] !== 'undefined')
94
+ result[LEGACY_FIND_OPTIONS_MAP[key]] = deepCopy(command[key]);
95
+ });
96
+
97
+ OP_QUERY_KEYS.forEach(key => {
98
+ if (command[key]) result[key] = command[key];
99
+ });
100
+
101
+ if (typeof command.pre32Limit !== 'undefined') {
102
+ result.limit = command.pre32Limit;
103
+ }
104
+
105
+ if (command.query.$explain) {
106
+ extractedCommand = { explain: result };
107
+ } else {
108
+ extractedCommand = result;
109
+ }
110
+ } else {
111
+ extractedCommand = deepCopy(command.query || command);
112
+ }
113
+
114
+ const commandName = Object.keys(extractedCommand)[0];
115
+ return {
116
+ cmd: extractedCommand,
117
+ name: commandName,
118
+ shouldRedact: shouldRedactCommand(commandName, extractedCommand)
119
+ };
120
+ };
121
+
122
+ module.exports = {
123
+ extractCommand
124
+ };
@@ -49,16 +49,16 @@ class MongoCredentials {
49
49
  this.mechanism = options.mechanism || 'default';
50
50
  this.mechanismProperties = options.mechanismProperties || {};
51
51
 
52
- if (this.mechanism.match(/MONGODB-AWS/i)) {
53
- if (this.username == null && process.env.AWS_ACCESS_KEY_ID) {
52
+ if (/MONGODB-AWS/i.test(this.mechanism)) {
53
+ if (!this.username && process.env.AWS_ACCESS_KEY_ID) {
54
54
  this.username = process.env.AWS_ACCESS_KEY_ID;
55
55
  }
56
56
 
57
- if (this.password == null && process.env.AWS_SECRET_ACCESS_KEY) {
57
+ if (!this.password && process.env.AWS_SECRET_ACCESS_KEY) {
58
58
  this.password = process.env.AWS_SECRET_ACCESS_KEY;
59
59
  }
60
60
 
61
- if (this.mechanismProperties.AWS_SESSION_TOKEN == null && process.env.AWS_SESSION_TOKEN) {
61
+ if (!this.mechanismProperties.AWS_SESSION_TOKEN && process.env.AWS_SESSION_TOKEN) {
62
62
  this.mechanismProperties.AWS_SESSION_TOKEN = process.env.AWS_SESSION_TOKEN;
63
63
  }
64
64
  }
@@ -90,7 +90,7 @@ class MongoCredentials {
90
90
  */
91
91
  resolveAuthMechanism(ismaster) {
92
92
  // If the mechanism is not "default", then it does not need to be resolved
93
- if (this.mechanism.match(/DEFAULT/i)) {
93
+ if (/DEFAULT/i.test(this.mechanism)) {
94
94
  return new MongoCredentials({
95
95
  username: this.username,
96
96
  password: this.password,