mongoose 6.3.8 → 6.4.1

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/lib/connection.js CHANGED
@@ -9,6 +9,7 @@ const EventEmitter = require('events').EventEmitter;
9
9
  const Schema = require('./schema');
10
10
  const STATES = require('./connectionstate');
11
11
  const MongooseError = require('./error/index');
12
+ const DisconnectedError = require('./error/disconnected');
12
13
  const SyncIndexesError = require('./error/syncIndexes');
13
14
  const PromiseProvider = require('./promise_provider');
14
15
  const ServerSelectionError = require('./error/serverSelection');
@@ -565,8 +566,7 @@ function _wrapConnHelper(fn) {
565
566
  const argsWithoutCb = typeof cb === 'function' ?
566
567
  Array.prototype.slice.call(arguments, 0, arguments.length - 1) :
567
568
  Array.prototype.slice.call(arguments);
568
- const disconnectedError = new MongooseError('Connection ' + this.id +
569
- ' was disconnected when calling `' + fn.name + '`');
569
+ const disconnectedError = new DisconnectedError(this.id, fn.name);
570
570
 
571
571
  return promiseOrCallback(cb, cb => {
572
572
  immediate(() => {
@@ -697,6 +697,18 @@ Connection.prototype.openUri = function(uri, options, callback) {
697
697
  typeof callback + '"');
698
698
  }
699
699
 
700
+ if (this._destroyCalled) {
701
+ const error = 'Connection has been closed and destroyed, and cannot be used for re-opening the connection. ' +
702
+ 'Please create a new connection with `mongoose.createConnection()` or `mongoose.connect()`.';
703
+ if (typeof callback === 'function') {
704
+ callback(error);
705
+ return;
706
+ }
707
+ else {
708
+ throw new MongooseError(error);
709
+ }
710
+ }
711
+
700
712
  if (this.readyState === STATES.connecting || this.readyState === STATES.connected) {
701
713
  if (this._connectionString !== uri) {
702
714
  throw new MongooseError('Can\'t call `openUri()` on an active connection with ' +
@@ -901,6 +913,23 @@ function _setClient(conn, client, options, dbName) {
901
913
  }
902
914
  }
903
915
 
916
+ Connection.prototype.destroy = function(force, callback) {
917
+ if (typeof force === 'function') {
918
+ callback = force;
919
+ force = false;
920
+ }
921
+
922
+ if (force != null && typeof force === 'object') {
923
+ this.$wasForceClosed = !!force.force;
924
+ } else {
925
+ this.$wasForceClosed = !!force;
926
+ }
927
+
928
+ return promiseOrCallback(callback, cb => {
929
+ this._close(force, true, cb);
930
+ });
931
+ };
932
+
904
933
  /**
905
934
  * Closes the connection
906
935
  *
@@ -923,7 +952,7 @@ Connection.prototype.close = function(force, callback) {
923
952
  }
924
953
 
925
954
  return promiseOrCallback(callback, cb => {
926
- this._close(force, cb);
955
+ this._close(force, false, cb);
927
956
  });
928
957
  };
929
958
 
@@ -931,19 +960,26 @@ Connection.prototype.close = function(force, callback) {
931
960
  * Handles closing the connection
932
961
  *
933
962
  * @param {Boolean} force
963
+ * @param {Boolean} destroy
934
964
  * @param {Function} callback
935
965
  * @api private
936
966
  */
937
- Connection.prototype._close = function(force, callback) {
967
+ Connection.prototype._close = function(force, destroy, callback) {
938
968
  const _this = this;
939
969
  const closeCalled = this._closeCalled;
940
970
  this._closeCalled = true;
971
+ this._destroyCalled = destroy;
941
972
  if (this.client != null) {
942
973
  this.client._closeCalled = true;
974
+ this.client._destroyCalled = destroy;
943
975
  }
944
976
 
977
+ const conn = this;
945
978
  switch (this.readyState) {
946
979
  case STATES.disconnected:
980
+ if (destroy && this.base.connections.indexOf(conn) !== -1) {
981
+ this.base.connections.splice(this.base.connections.indexOf(conn), 1);
982
+ }
947
983
  if (closeCalled) {
948
984
  callback();
949
985
  } else {
@@ -963,6 +999,9 @@ Connection.prototype._close = function(force, callback) {
963
999
  if (err) {
964
1000
  return callback(err);
965
1001
  }
1002
+ if (destroy && _this.base.connections.indexOf(conn) !== -1) {
1003
+ _this.base.connections.splice(_this.base.connections.indexOf(conn), 1);
1004
+ }
966
1005
  _this.onClose(force);
967
1006
  callback(null);
968
1007
  });
@@ -970,12 +1009,15 @@ Connection.prototype._close = function(force, callback) {
970
1009
  break;
971
1010
  case STATES.connecting:
972
1011
  this.once('open', function() {
973
- _this.close(callback);
1012
+ destroy ? _this.destroy(force, callback) : _this.close(force, callback);
974
1013
  });
975
1014
  break;
976
1015
 
977
1016
  case STATES.disconnecting:
978
1017
  this.once('close', function() {
1018
+ if (destroy && _this.base.connections.indexOf(conn) !== -1) {
1019
+ _this.base.connections.splice(_this.base.connections.indexOf(conn), 1);
1020
+ }
979
1021
  callback();
980
1022
  });
981
1023
  break;
@@ -1004,7 +1046,7 @@ Connection.prototype.onClose = function(force) {
1004
1046
  this.emit('close', force);
1005
1047
 
1006
1048
  for (const db of this.otherDbs) {
1007
- db.close({ force: force, skipCloseClient: true });
1049
+ this._destroyCalled ? db.destroy({ force: force, skipCloseClient: true }) : db.close({ force: force, skipCloseClient: true });
1008
1050
  }
1009
1051
  };
1010
1052
 
@@ -1026,7 +1068,7 @@ Connection.prototype.collection = function(name, options) {
1026
1068
  };
1027
1069
  options = Object.assign({}, defaultOptions, options ? utils.clone(options) : {});
1028
1070
  options.$wasForceClosed = this.$wasForceClosed;
1029
- const Collection = driver.get().Collection;
1071
+ const Collection = this.base && this.base.__driver && this.base.__driver.Collection || driver.get().Collection;
1030
1072
  if (!(name in this.collections)) {
1031
1073
  this.collections[name] = new Collection(name, this, options);
1032
1074
  }
@@ -1260,8 +1302,7 @@ Connection.prototype.deleteModel = function(name) {
1260
1302
  */
1261
1303
 
1262
1304
  Connection.prototype.watch = function(pipeline, options) {
1263
- const disconnectedError = new MongooseError('Connection ' + this.id +
1264
- ' was disconnected when calling `watch()`');
1305
+ const disconnectedError = new DisconnectedError(this.id, 'watch');
1265
1306
 
1266
1307
  const changeStreamThunk = cb => {
1267
1308
  immediate(() => {
package/lib/document.js CHANGED
@@ -1035,6 +1035,7 @@ Document.prototype.overwrite = function overwrite(obj) {
1035
1035
  * @param {Any} val the value to set
1036
1036
  * @param {Schema|String|Number|Buffer|*} [type] optionally specify a type for "on-the-fly" attributes
1037
1037
  * @param {Object} [options] optionally specify options that modify the behavior of the set
1038
+ * @param {Boolean} [options.merge=false] if true, setting a [nested path](/docs/subdocs.html#subdocuments-versus-nested-paths) will merge existing values rather than overwrite the whole object. So `doc.set('nested', { a: 1, b: 2 })` becomes `doc.set('nested.a', 1); doc.set('nested.b', 2);`
1038
1039
  * @method $set
1039
1040
  * @name $set
1040
1041
  * @memberOf Document
@@ -2486,7 +2487,7 @@ function _getPathsToValidate(doc) {
2486
2487
  const fullPathToSubdoc = subdoc.$__fullPathWithIndexes();
2487
2488
 
2488
2489
  for (const p of paths) {
2489
- if (p === null || p.startsWith(fullPathToSubdoc + '.')) {
2490
+ if (p == null || p.startsWith(fullPathToSubdoc + '.')) {
2490
2491
  paths.delete(p);
2491
2492
  }
2492
2493
  }
@@ -2507,6 +2508,14 @@ function _getPathsToValidate(doc) {
2507
2508
  continue;
2508
2509
  }
2509
2510
 
2511
+ if (_pathType.$isMongooseDocumentArray) {
2512
+ for (const p of paths) {
2513
+ if (p == null || p.startsWith(_pathType.path + '.')) {
2514
+ paths.delete(p);
2515
+ }
2516
+ }
2517
+ }
2518
+
2510
2519
  // Optimization: if primitive path with no validators, or array of primitives
2511
2520
  // with no validators, skip validating this path entirely.
2512
2521
  if (!_pathType.caster && _pathType.validators.length === 0) {
@@ -3145,8 +3154,7 @@ Document.prototype.$__reset = function reset() {
3145
3154
  if (subdoc.$isDocumentArrayElement) {
3146
3155
  if (!resetArrays.has(subdoc.parentArray())) {
3147
3156
  const array = subdoc.parentArray();
3148
- // Mark path to array as init for gh-6818
3149
- this.$__.activePaths.init(fullPathWithIndexes.replace(/\.\d+$/, '').slice(-subdoc.$basePath - 1));
3157
+ this.$__.activePaths.clearPath(fullPathWithIndexes.replace(/\.\d+$/, '').slice(-subdoc.$basePath - 1));
3150
3158
  array[arrayAtomicsBackupSymbol] = array[arrayAtomicsSymbol];
3151
3159
  array[arrayAtomicsSymbol] = {};
3152
3160
 
@@ -3154,7 +3162,7 @@ Document.prototype.$__reset = function reset() {
3154
3162
  }
3155
3163
  } else {
3156
3164
  if (subdoc.$parent() === this) {
3157
- this.$__.activePaths.init(subdoc.$basePath);
3165
+ this.$__.activePaths.clearPath(subdoc.$basePath);
3158
3166
  } else if (subdoc.$parent() != null && subdoc.$parent().$isSubdocument) {
3159
3167
  // If map path underneath subdocument, may end up with a case where
3160
3168
  // map path is modified but parent still needs to be reset. See gh-10295
@@ -3388,7 +3396,7 @@ Document.prototype.$getAllSubdocs = function() {
3388
3396
  }, seed);
3389
3397
  } else if (val && !Array.isArray(val) && val.$isSingleNested) {
3390
3398
  seed = Object.keys(val._doc).reduce(function(seed, path) {
3391
- return docReducer(val._doc, seed, path);
3399
+ return docReducer(val, seed, path);
3392
3400
  }, seed);
3393
3401
  seed.push(val);
3394
3402
  } else if (val && utils.isMongooseDocumentArray(val)) {
@@ -4262,10 +4270,10 @@ Document.prototype.$getPopulatedDocs = function $getPopulatedDocs() {
4262
4270
  *
4263
4271
  * #### Example:
4264
4272
  *
4265
- * Model.findOne().populate('author').exec(function (err, doc) {
4266
- * console.log(doc.author.name) // Dr.Seuss
4267
- * console.log(doc.populated('author')) // '5144cf8050f071d979c118a7'
4268
- * })
4273
+ * const doc = await Model.findOne().populate('author');
4274
+ *
4275
+ * console.log(doc.author.name); // Dr.Seuss
4276
+ * console.log(doc.populated('author')); // '5144cf8050f071d979c118a7'
4269
4277
  *
4270
4278
  * If the path was not populated, returns `undefined`.
4271
4279
  *
@@ -4319,6 +4327,38 @@ Document.prototype.populated = function(path, val, options) {
4319
4327
 
4320
4328
  Document.prototype.$populated = Document.prototype.populated;
4321
4329
 
4330
+ /**
4331
+ * Throws an error if a given path is not populated
4332
+ *
4333
+ * #### Example:
4334
+ *
4335
+ * const doc = await Model.findOne().populate('author');
4336
+ *
4337
+ * doc.$assertPopulated('author'); // does not throw
4338
+ * doc.$assertPopulated('other path'); // throws an error
4339
+ *
4340
+ *
4341
+ * @param {String|Array<String>} path
4342
+ * @return {Document} this
4343
+ * @memberOf Document
4344
+ * @method $assertPopulated
4345
+ * @instance
4346
+ * @api public
4347
+ */
4348
+
4349
+ Document.prototype.$assertPopulated = function $assertPopulated(paths) {
4350
+ if (Array.isArray(paths)) {
4351
+ paths.forEach(path => this.$assertPopulated(path));
4352
+ return this;
4353
+ }
4354
+
4355
+ if (!this.$populated(paths)) {
4356
+ throw new MongooseError(`Expected path "${paths}" to be populated`);
4357
+ }
4358
+
4359
+ return this;
4360
+ };
4361
+
4322
4362
  /**
4323
4363
  * Takes a populated field and returns it to its unpopulated state.
4324
4364
  *
@@ -16,10 +16,9 @@ class DisconnectedError extends MongooseError {
16
16
  /**
17
17
  * @param {String} connectionString
18
18
  */
19
- constructor(connectionString) {
20
- super('Ran out of retries trying to reconnect to "' +
21
- connectionString + '". Try setting `server.reconnectTries` and ' +
22
- '`server.reconnectInterval` to something higher.');
19
+ constructor(id, fnName) {
20
+ super('Connection ' + id +
21
+ ' was disconnected when calling `' + fnName + '()`');
23
22
  }
24
23
  }
25
24
 
@@ -31,8 +31,11 @@ module.exports = function setupTimestamps(schema, timestamps) {
31
31
  }
32
32
 
33
33
  if (createdAt && !schema.paths[createdAt]) {
34
- schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable: true };
34
+ const baseImmutableCreatedAt = schema.base.get('timestamps.createdAt.immutable');
35
+ const immutable = baseImmutableCreatedAt != null ? baseImmutableCreatedAt : true;
36
+ schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable };
35
37
  }
38
+
36
39
  schema.add(schemaAdditions);
37
40
 
38
41
  schema.pre('save', function(next) {
@@ -125,26 +125,19 @@ module.exports = function(query, schema, castedDoc, options, callback) {
125
125
  validatorsToExecute.push(function(callback) {
126
126
  schemaPath.doValidate(v, function(err) {
127
127
  if (err) {
128
- err.path = updates[i];
129
- validationErrors.push(err);
130
- return callback(null);
131
- }
132
-
133
- v.validate(function(err) {
134
- if (err) {
135
- if (err.errors) {
136
- for (const key of Object.keys(err.errors)) {
137
- const _err = err.errors[key];
138
- _err.path = updates[i] + '.' + key;
139
- validationErrors.push(_err);
140
- }
141
- } else {
142
- err.path = updates[i];
143
- validationErrors.push(err);
128
+ if (err.errors) {
129
+ for (const key of Object.keys(err.errors)) {
130
+ const _err = err.errors[key];
131
+ _err.path = updates[i] + '.' + key;
132
+ validationErrors.push(_err);
144
133
  }
134
+ } else {
135
+ err.path = updates[i];
136
+ validationErrors.push(err);
145
137
  }
146
- callback(null);
147
- });
138
+ }
139
+
140
+ return callback(null);
148
141
  }, context, { updateValidator: true });
149
142
  });
150
143
  } else {
package/lib/index.js CHANGED
@@ -8,6 +8,7 @@ require('./driver').set(require('./drivers/node-mongodb-native'));
8
8
 
9
9
  const Document = require('./document');
10
10
  const EventEmitter = require('events').EventEmitter;
11
+ const Kareem = require('kareem');
11
12
  const Schema = require('./schema');
12
13
  const SchemaType = require('./schematype');
13
14
  const SchemaTypes = require('./schema/index');
@@ -35,6 +36,7 @@ const shardingPlugin = require('./plugins/sharding');
35
36
  const trusted = require('./helpers/query/trusted').trusted;
36
37
  const sanitizeFilter = require('./helpers/query/sanitizeFilter');
37
38
  const isBsonType = require('./helpers/isBsonType');
39
+ const MongooseError = require('./error/mongooseError');
38
40
 
39
41
  const defaultMongooseSymbol = Symbol.for('mongoose:default');
40
42
 
@@ -62,6 +64,7 @@ function Mongoose(options) {
62
64
  this.connections = [];
63
65
  this.models = {};
64
66
  this.events = new EventEmitter();
67
+ this.__driver = driver.get();
65
68
  // default global options
66
69
  this.options = Object.assign({
67
70
  pluralization: true,
@@ -135,6 +138,7 @@ Mongoose.prototype.ConnectionStates = STATES;
135
138
  * uses to communicate with the database. A driver is a Mongoose-specific interface that defines functions
136
139
  * like `find()`.
137
140
  *
141
+ * @deprecated
138
142
  * @memberOf Mongoose
139
143
  * @property driver
140
144
  * @api public
@@ -142,6 +146,36 @@ Mongoose.prototype.ConnectionStates = STATES;
142
146
 
143
147
  Mongoose.prototype.driver = driver;
144
148
 
149
+ /**
150
+ * Overwrites the current driver used by this Mongoose instance. A driver is a
151
+ * Mongoose-specific interface that defines functions like `find()`.
152
+ *
153
+ * @memberOf Mongoose
154
+ * @method setDriver
155
+ * @api public
156
+ */
157
+
158
+ Mongoose.prototype.setDriver = function setDriver(driver) {
159
+ const _mongoose = this instanceof Mongoose ? this : mongoose;
160
+
161
+ if (_mongoose.__driver === driver) {
162
+ return _mongoose;
163
+ }
164
+
165
+ const openConnection = _mongoose.connections && _mongoose.connections.find(conn => conn.readyState !== STATES.disconnected);
166
+ if (openConnection) {
167
+ const msg = 'Cannot modify Mongoose driver if a connection is already open. ' +
168
+ 'Call `mongoose.disconnect()` before modifying the driver';
169
+ throw new MongooseError(msg);
170
+ }
171
+ _mongoose.__driver = driver;
172
+
173
+ const Connection = driver.getConnection();
174
+ _mongoose.connections = [new Connection(_mongoose)];
175
+
176
+ return _mongoose;
177
+ };
178
+
145
179
  /**
146
180
  * Sets mongoose options
147
181
  *
@@ -154,23 +188,26 @@ Mongoose.prototype.driver = driver;
154
188
  * mongoose.set('debug', function(collectionName, methodName, ...methodArgs) {}); // use custom function to log collection methods + arguments
155
189
  *
156
190
  * Currently supported options are:
191
+ * - 'applyPluginsToChildSchemas': `true` by default. Set to false to skip applying global plugins to child schemas
192
+ * - 'applyPluginsToDiscriminators': `false` by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
193
+ * - 'autoCreate': Set to `true` to make Mongoose call [`Model.createCollection()`](/docs/api/model.html#model_Model.createCollection) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist.
194
+ * - 'autoIndex': `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
157
195
  * - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arguments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
158
196
  * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
159
197
  * - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
160
- * - 'cloneSchemas': false by default. Set to `true` to `clone()` all schemas before compiling into a model.
161
- * - 'applyPluginsToDiscriminators': false by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema.
162
- * - 'applyPluginsToChildSchemas': true by default. Set to false to skip applying global plugins to child schemas
163
- * - 'objectIdGetter': true by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
164
- * - 'runValidators': false by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
165
- * - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
166
- * - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
167
- * - 'strict': true by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
168
- * - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas.
169
- * - 'selectPopulatedPaths': true by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
198
+ * - 'cloneSchemas': `false` by default. Set to `true` to `clone()` all schemas before compiling into a model.
199
+ * - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arugments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
200
+ * - 'timestamps.createdAt.immutable': `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable) which means you can update the `createdAt`
170
201
  * - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
171
- * - 'autoIndex': true by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance.
172
- * - 'autoCreate': Set to `true` to make Mongoose call [`Model.createCollection()`](/docs/api/model.html#model_Model.createCollection) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist.
202
+ * - 'objectIdGetter': `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
173
203
  * - 'overwriteModels': Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
204
+ * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information.
205
+ * - 'runValidators': `false` by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default.
206
+ * - 'selectPopulatedPaths': `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
207
+ * - 'strict': `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
208
+ * - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas.
209
+ * - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
210
+ * - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
174
211
  *
175
212
  * @param {String} key
176
213
  * @param {String|Function|Boolean} value
@@ -260,8 +297,6 @@ Mongoose.prototype.get = Mongoose.prototype.set;
260
297
  * @param {String} [options.user] username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility.
261
298
  * @param {String} [options.pass] password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility.
262
299
  * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
263
- * @param {Number} [options.reconnectTries=30] If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
264
- * @param {Number} [options.reconnectInterval=1000] See `reconnectTries` option above.
265
300
  * @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
266
301
  * @param {Number} [options.maxPoolSize=5] The maximum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
267
302
  * @param {Number} [options.minPoolSize=1] The minimum number of sockets the MongoDB driver will keep open for this connection. Keep in mind that MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](https://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
@@ -275,7 +310,7 @@ Mongoose.prototype.get = Mongoose.prototype.set;
275
310
  Mongoose.prototype.createConnection = function(uri, options, callback) {
276
311
  const _mongoose = this instanceof Mongoose ? this : mongoose;
277
312
 
278
- const Connection = driver.get().getConnection();
313
+ const Connection = _mongoose.__driver.getConnection();
279
314
  const conn = new Connection(_mongoose);
280
315
  if (typeof options === 'function') {
281
316
  callback = options;
@@ -323,8 +358,6 @@ Mongoose.prototype.createConnection = function(uri, options, callback) {
323
358
  * @param {Number} [options.serverSelectionTimeoutMS] If `useUnifiedTopology = true`, the MongoDB driver will try to find a server to send any given operation to, and keep retrying for `serverSelectionTimeoutMS` milliseconds before erroring out. If not set, the MongoDB driver defaults to using `30000` (30 seconds).
324
359
  * @param {Number} [options.heartbeatFrequencyMS] If `useUnifiedTopology = true`, the MongoDB driver sends a heartbeat every `heartbeatFrequencyMS` to check on the status of the connection. A heartbeat is subject to `serverSelectionTimeoutMS`, so the MongoDB driver will retry failed heartbeats for up to 30 seconds by default. Mongoose only emits a `'disconnected'` event after a heartbeat has failed, so you may want to decrease this setting to reduce the time between when your server goes down and when Mongoose emits `'disconnected'`. We recommend you do **not** set this setting below 1000, too many heartbeats can lead to performance degradation.
325
360
  * @param {Boolean} [options.autoIndex=true] Mongoose-specific option. Set to false to disable automatic index creation for all models associated with this connection.
326
- * @param {Number} [options.reconnectTries=30] If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every `reconnectInterval` milliseconds for `reconnectTries` times, and give up afterward. When the driver gives up, the mongoose connection emits a `reconnectFailed` event. This option does nothing for replica set connections.
327
- * @param {Number} [options.reconnectInterval=1000] See `reconnectTries` option above.
328
361
  * @param {Class} [options.promiseLibrary] Sets the [underlying driver's promise library](https://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
329
362
  * @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
330
363
  * @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
@@ -471,7 +504,6 @@ Mongoose.prototype.pluralize = function(fn) {
471
504
  */
472
505
 
473
506
  Mongoose.prototype.model = function(name, schema, collection, options) {
474
-
475
507
  const _mongoose = this instanceof Mongoose ? this : mongoose;
476
508
 
477
509
  if (typeof schema === 'string') {
@@ -688,7 +720,7 @@ Mongoose.prototype.__defineGetter__('connection', function() {
688
720
  });
689
721
 
690
722
  Mongoose.prototype.__defineSetter__('connection', function(v) {
691
- if (v instanceof Connection) {
723
+ if (v instanceof this.__driver.getConnection()) {
692
724
  this.connections[0] = v;
693
725
  this.models = v.models;
694
726
  }
@@ -717,18 +749,6 @@ Mongoose.prototype.__defineSetter__('connection', function(v) {
717
749
 
718
750
  Mongoose.prototype.connections;
719
751
 
720
- /*!
721
- * Connection
722
- */
723
-
724
- const Connection = driver.get().getConnection();
725
-
726
- /*!
727
- * Collection
728
- */
729
-
730
- const Collection = driver.get().Collection;
731
-
732
752
  /**
733
753
  * The Mongoose Aggregate constructor
734
754
  *
@@ -745,7 +765,14 @@ Mongoose.prototype.Aggregate = Aggregate;
745
765
  * @api public
746
766
  */
747
767
 
748
- Mongoose.prototype.Collection = Collection;
768
+ Object.defineProperty(Mongoose.prototype, 'Collection', {
769
+ get: function() {
770
+ return this.__driver.Collection;
771
+ },
772
+ set: function(Collection) {
773
+ this.__driver.Collection = Collection;
774
+ }
775
+ });
749
776
 
750
777
  /**
751
778
  * The Mongoose [Connection](#connection_Connection) constructor
@@ -756,7 +783,18 @@ Mongoose.prototype.Collection = Collection;
756
783
  * @api public
757
784
  */
758
785
 
759
- Mongoose.prototype.Connection = Connection;
786
+ Object.defineProperty(Mongoose.prototype, 'Connection', {
787
+ get: function() {
788
+ return this.__driver.getConnection();
789
+ },
790
+ set: function(Connection) {
791
+ if (Connection === this.__driver.getConnection()) {
792
+ return;
793
+ }
794
+
795
+ this.__driver.getConnection = () => Connection;
796
+ }
797
+ });
760
798
 
761
799
  /**
762
800
  * The Mongoose version
@@ -1182,6 +1220,43 @@ Mongoose.prototype._promiseOrCallback = function(callback, fn, ee) {
1182
1220
  return promiseOrCallback(callback, fn, ee, this.Promise);
1183
1221
  };
1184
1222
 
1223
+ /**
1224
+ * Use this function in `pre()` middleware to skip calling the wrapped function.
1225
+ *
1226
+ * ####Example:
1227
+ *
1228
+ * schema.pre('save', function() {
1229
+ * // Will skip executing `save()`, but will execute post hooks as if
1230
+ * // `save()` had executed with the result `{ matchedCount: 0 }`
1231
+ * return mongoose.skipMiddlewareFunction({ matchedCount: 0 });
1232
+ * });
1233
+ *
1234
+ * @method skipMiddlewareFunction
1235
+ * @param {any} result
1236
+ * @api public
1237
+ */
1238
+
1239
+ Mongoose.prototype.skipMiddlewareFunction = Kareem.skipWrappedFunction;
1240
+
1241
+ /**
1242
+ * Use this function in `post()` middleware to replace the result
1243
+ *
1244
+ * ####Example:
1245
+ *
1246
+ * schema.post('find', function(res) {
1247
+ * // Normally you have to modify `res` in place. But with
1248
+ * // `overwriteMiddlewarResult()`, you can make `find()` return a
1249
+ * // completely different value.
1250
+ * return mongoose.overwriteMiddlewareResult(res.filter(doc => !doc.isDeleted));
1251
+ * });
1252
+ *
1253
+ * @method overwriteMiddlewareResult
1254
+ * @param {any} result
1255
+ * @api public
1256
+ */
1257
+
1258
+ Mongoose.prototype.overwriteMiddlewareResult = Kareem.overwriteResult;
1259
+
1185
1260
  /*!
1186
1261
  * The exports object is an instance of Mongoose.
1187
1262
  *
package/lib/model.js CHANGED
@@ -4281,7 +4281,7 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) {
4281
4281
 
4282
4282
  for (const path of paths) {
4283
4283
  const schemaType = schema.path(path);
4284
- if (!schemaType || !schemaType.$isMongooseArray) {
4284
+ if (!schemaType || !schemaType.$isMongooseArray || schemaType.$isMongooseDocumentArray) {
4285
4285
  continue;
4286
4286
  }
4287
4287