mongoose 6.1.10 → 6.2.3

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 (81) hide show
  1. package/.eslintrc.json +154 -0
  2. package/CHANGELOG.md +73 -0
  3. package/dist/browser.umd.js +233 -222
  4. package/index.js +5 -1
  5. package/lib/aggregate.js +23 -28
  6. package/lib/browserDocument.js +1 -1
  7. package/lib/cast/number.js +2 -3
  8. package/lib/cast.js +9 -7
  9. package/lib/connection.js +76 -24
  10. package/lib/cursor/AggregationCursor.js +12 -7
  11. package/lib/cursor/QueryCursor.js +11 -6
  12. package/lib/document.js +131 -122
  13. package/lib/drivers/node-mongodb-native/collection.js +12 -4
  14. package/lib/drivers/node-mongodb-native/connection.js +11 -0
  15. package/lib/error/cast.js +3 -2
  16. package/lib/error/index.js +11 -0
  17. package/lib/error/syncIndexes.js +30 -0
  18. package/lib/helpers/clone.js +51 -29
  19. package/lib/helpers/common.js +2 -2
  20. package/lib/helpers/cursor/eachAsync.js +18 -15
  21. package/lib/helpers/document/compile.js +7 -4
  22. package/lib/helpers/getFunctionName.js +6 -4
  23. package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +14 -0
  24. package/lib/helpers/indexes/getRelatedIndexes.js +59 -0
  25. package/lib/helpers/isMongooseObject.js +9 -8
  26. package/lib/helpers/isObject.js +4 -4
  27. package/lib/helpers/model/discriminator.js +2 -1
  28. package/lib/helpers/path/parentPaths.js +10 -5
  29. package/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -2
  30. package/lib/helpers/populate/assignVals.js +12 -4
  31. package/lib/helpers/populate/getModelsMapForPopulate.js +4 -4
  32. package/lib/helpers/populate/markArraySubdocsPopulated.js +3 -1
  33. package/lib/helpers/populate/modelNamesFromRefPath.js +4 -3
  34. package/lib/helpers/printJestWarning.js +2 -2
  35. package/lib/helpers/projection/applyProjection.js +77 -0
  36. package/lib/helpers/projection/hasIncludedChildren.js +36 -0
  37. package/lib/helpers/projection/isExclusive.js +5 -2
  38. package/lib/helpers/projection/isInclusive.js +5 -1
  39. package/lib/helpers/query/cast$expr.js +279 -0
  40. package/lib/helpers/query/castUpdate.js +6 -2
  41. package/lib/helpers/query/hasDollarKeys.js +7 -3
  42. package/lib/helpers/query/isOperator.js +5 -2
  43. package/lib/helpers/schema/applyPlugins.js +11 -0
  44. package/lib/helpers/schema/getIndexes.js +6 -2
  45. package/lib/helpers/schema/getPath.js +4 -2
  46. package/lib/helpers/timestamps/setupTimestamps.js +3 -8
  47. package/lib/index.js +26 -19
  48. package/lib/internal.js +10 -2
  49. package/lib/model.js +196 -171
  50. package/lib/options/SchemaTypeOptions.js +1 -1
  51. package/lib/plugins/trackTransaction.js +5 -4
  52. package/lib/query.js +159 -146
  53. package/lib/queryhelpers.js +10 -10
  54. package/lib/schema/SubdocumentPath.js +4 -3
  55. package/lib/schema/array.js +30 -21
  56. package/lib/schema/buffer.js +1 -1
  57. package/lib/schema/date.js +1 -1
  58. package/lib/schema/decimal128.js +1 -1
  59. package/lib/schema/documentarray.js +9 -11
  60. package/lib/schema/number.js +1 -1
  61. package/lib/schema/objectid.js +2 -2
  62. package/lib/schema/string.js +4 -4
  63. package/lib/schema.js +13 -8
  64. package/lib/schematype.js +86 -40
  65. package/lib/types/ArraySubdocument.js +2 -1
  66. package/lib/types/DocumentArray/index.js +10 -27
  67. package/lib/types/DocumentArray/isMongooseDocumentArray.js +5 -0
  68. package/lib/types/DocumentArray/methods/index.js +15 -3
  69. package/lib/types/array/index.js +22 -21
  70. package/lib/types/array/isMongooseArray.js +5 -0
  71. package/lib/types/array/methods/index.js +22 -23
  72. package/lib/types/buffer.js +3 -3
  73. package/lib/types/map.js +3 -4
  74. package/lib/utils.js +19 -10
  75. package/package.json +34 -168
  76. package/tools/repl.js +1 -1
  77. package/tsconfig.json +8 -0
  78. package/types/Error.d.ts +129 -0
  79. package/types/PipelineStage.d.ts +272 -0
  80. package/{index.d.ts → types/index.d.ts} +169 -481
  81. package/lib/types/array/ArrayWrapper.js +0 -981
@@ -26,9 +26,9 @@ exports.preparePopulationOptions = function preparePopulationOptions(query, opti
26
26
 
27
27
  // lean options should trickle through all queries
28
28
  if (options.lean != null) {
29
- pop.
30
- filter(p => get(p, 'options.lean') == null).
31
- forEach(makeLean(options.lean));
29
+ pop
30
+ .filter(p => (p && p.options && p.options.lean) == null)
31
+ .forEach(makeLean(options.lean));
32
32
  }
33
33
 
34
34
  pop.forEach(opts => {
@@ -53,12 +53,12 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query,
53
53
 
54
54
  // lean options should trickle through all queries
55
55
  if (options.lean != null) {
56
- pop.
57
- filter(p => get(p, 'options.lean') == null).
58
- forEach(makeLean(options.lean));
56
+ pop
57
+ .filter(p => (p && p.options && p.options.lean) == null)
58
+ .forEach(makeLean(options.lean));
59
59
  }
60
60
 
61
- const session = get(query, 'options.session', null);
61
+ const session = query && query.options && query.options.session || null;
62
62
  if (session != null) {
63
63
  pop.forEach(path => {
64
64
  if (path.options == null) {
@@ -212,7 +212,7 @@ exports.applyPaths = function applyPaths(fields, schema) {
212
212
 
213
213
  let addedPath = analyzePath(path, type);
214
214
  // arrays
215
- if (addedPath == null && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
215
+ if (addedPath == null && !Array.isArray(type) && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
216
216
  addedPath = analyzePath(path, type.caster);
217
217
  }
218
218
  if (addedPath != null) {
@@ -272,7 +272,7 @@ exports.applyPaths = function applyPaths(fields, schema) {
272
272
  // Special case: if user has included a parent path of a discriminator key,
273
273
  // don't explicitly project in the discriminator key because that will
274
274
  // project out everything else under the parent path
275
- if (!exclude && get(type, 'options.$skipDiscriminatorCheck', false)) {
275
+ if (!exclude && (type && type.options && type.options.$skipDiscriminatorCheck || false)) {
276
276
  let cur = '';
277
277
  for (let i = 0; i < pieces.length; ++i) {
278
278
  cur += (cur.length === 0 ? '' : '.') + pieces[i];
@@ -319,7 +319,7 @@ exports.handleDeleteWriteOpResult = function handleDeleteWriteOpResult(callback)
319
319
  return callback(error);
320
320
  }
321
321
  const mongooseResult = Object.assign({}, res.result);
322
- if (get(res, 'result.n', null) != null) {
322
+ if ((res && res.result && res.result.n || null) != null) {
323
323
  mongooseResult.deletedCount = res.result.n;
324
324
  }
325
325
  if (res.deletedCount != null) {
@@ -13,7 +13,6 @@ const $exists = require('./operators/exists');
13
13
  const castToNumber = require('./operators/helpers').castToNumber;
14
14
  const discriminator = require('../helpers/model/discriminator');
15
15
  const geospatial = require('./operators/geospatial');
16
- const get = require('../helpers/get');
17
16
  const getConstructor = require('../helpers/discriminator/getConstructor');
18
17
  const handleIdOption = require('../helpers/schema/handleIdOption');
19
18
  const internalToObjectOptions = require('../options').internalToObjectOptions;
@@ -164,7 +163,7 @@ SubdocumentPath.prototype.cast = function(val, doc, init, priorVal, options) {
164
163
  let subdoc;
165
164
 
166
165
  // Only pull relevant selected paths and pull out the base path
167
- const parentSelected = get(doc, '$__.selected', {});
166
+ const parentSelected = doc && doc.$__ && doc.$__.selected || {};
168
167
  const path = this.path;
169
168
  const selected = Object.keys(parentSelected).reduce((obj, key) => {
170
169
  if (key.startsWith(path + '.')) {
@@ -301,7 +300,9 @@ SubdocumentPath.prototype.doValidateSync = function(value, scope, options) {
301
300
  SubdocumentPath.prototype.discriminator = function(name, schema, options) {
302
301
  options = options || {};
303
302
  const value = utils.isPOJO(options) ? options.value : options;
304
- const clone = get(options, 'clone', true);
303
+ const clone = typeof options.clone === 'boolean'
304
+ ? options.clone
305
+ : true;
305
306
 
306
307
  if (schema.instanceOfSchema && clone) {
307
308
  schema = schema.clone();
@@ -13,7 +13,6 @@ const CastError = SchemaType.CastError;
13
13
  const Mixed = require('./mixed');
14
14
  const arrayDepth = require('../helpers/arrayDepth');
15
15
  const cast = require('../cast');
16
- const get = require('../helpers/get');
17
16
  const isOperator = require('../helpers/query/isOperator');
18
17
  const util = require('util');
19
18
  const utils = require('../utils');
@@ -112,14 +111,12 @@ function SchemaArray(key, cast, options, schemaOptions) {
112
111
 
113
112
  if (!('defaultValue' in this) || this.defaultValue !== void 0) {
114
113
  const defaultFn = function() {
115
- let arr = [];
116
- if (fn) {
117
- arr = defaultArr.call(this);
118
- } else if (defaultArr != null) {
119
- arr = arr.concat(defaultArr);
120
- }
121
114
  // Leave it up to `cast()` to convert the array
122
- return arr;
115
+ return fn
116
+ ? defaultArr.call(this)
117
+ : defaultArr != null
118
+ ? [].concat(defaultArr)
119
+ : [];
123
120
  };
124
121
  defaultFn.$runBeforeSetters = !fn;
125
122
  this.default(defaultFn);
@@ -220,7 +217,7 @@ SchemaArray.prototype.checkRequired = function checkRequired(value, doc) {
220
217
 
221
218
  // `require('util').inherits()` does **not** copy static properties, and
222
219
  // plugins like mongoose-float use `inherits()` for pre-ES6.
223
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
220
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
224
221
  this.constructor.checkRequired() :
225
222
  SchemaArray.checkRequired();
226
223
 
@@ -238,7 +235,9 @@ SchemaArray.prototype.checkRequired = function checkRequired(value, doc) {
238
235
  SchemaArray.prototype.enum = function() {
239
236
  let arr = this;
240
237
  while (true) {
241
- const instance = get(arr, 'caster.instance');
238
+ const instance = arr &&
239
+ arr.caster &&
240
+ arr.caster.instance;
242
241
  if (instance === 'Array') {
243
242
  arr = arr.caster;
244
243
  continue;
@@ -275,7 +274,7 @@ SchemaArray.prototype.applyGetters = function(value, scope) {
275
274
 
276
275
  const ret = SchemaType.prototype.applyGetters.call(this, value, scope);
277
276
  if (Array.isArray(ret)) {
278
- const rawValue = ret.isMongooseArrayProxy ? ret.__array : ret;
277
+ const rawValue = utils.isMongooseArray(ret) ? ret.__array : ret;
279
278
  const len = rawValue.length;
280
279
  for (let i = 0; i < len; ++i) {
281
280
  rawValue[i] = this.caster.applyGetters(rawValue[i], scope);
@@ -299,7 +298,7 @@ SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
299
298
  }
300
299
 
301
300
  // No need to wrap empty arrays
302
- if (value != null && value.length > 0) {
301
+ if (value != null && value.length !== 0) {
303
302
  const valueDepth = arrayDepth(value);
304
303
  if (valueDepth.min === valueDepth.max && valueDepth.max < depth && valueDepth.containsNonArrayItem) {
305
304
  for (let i = valueDepth.max; i < depth; ++i) {
@@ -357,7 +356,7 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
357
356
 
358
357
  options = options || emptyOpts;
359
358
 
360
- let rawValue = value.isMongooseArrayProxy ? value.__array : value;
359
+ let rawValue = utils.isMongooseArray(value) ? value.__array : value;
361
360
  value = MongooseArray(rawValue, options.path || this._arrayPath || this.path, doc, this);
362
361
  rawValue = value.__array;
363
362
 
@@ -557,12 +556,16 @@ function cast$all(val) {
557
556
  }
558
557
 
559
558
  val = val.map(function(v) {
560
- if (utils.isObject(v)) {
561
- const o = {};
562
- o[this.path] = v;
563
- return cast(this.casterConstructor.schema, o)[this.path];
559
+ if (!utils.isObject(v)) {
560
+ return v;
561
+ }
562
+ if (v.$elemMatch != null) {
563
+ return { $elemMatch: cast(this.casterConstructor.schema, v.$elemMatch) };
564
564
  }
565
- return v;
565
+
566
+ const o = {};
567
+ o[this.path] = v;
568
+ return cast(this.casterConstructor.schema, o)[this.path];
566
569
  }, this);
567
570
 
568
571
  return this.castForQuery(val);
@@ -581,9 +584,15 @@ function cast$elemMatch(val) {
581
584
 
582
585
  // Is this an embedded discriminator and is the discriminator key set?
583
586
  // If so, use the discriminator schema. See gh-7449
584
- const discriminatorKey = get(this,
585
- 'casterConstructor.schema.options.discriminatorKey');
586
- const discriminators = get(this, 'casterConstructor.schema.discriminators', {});
587
+ const discriminatorKey = this &&
588
+ this.casterConstructor &&
589
+ this.casterConstructor.schema &&
590
+ this.casterConstructor.schema.options &&
591
+ this.casterConstructor.schema.options.discriminatorKey;
592
+ const discriminators = this &&
593
+ this.casterConstructor &&
594
+ this.casterConstructor.schema &&
595
+ this.casterConstructor.schema.discriminators || {};
587
596
  if (discriminatorKey != null &&
588
597
  val[discriminatorKey] != null &&
589
598
  discriminators[val[discriminatorKey]] != null) {
@@ -202,7 +202,7 @@ SchemaBuffer.prototype.cast = function(value, doc, init) {
202
202
 
203
203
  /**
204
204
  * Sets the default [subtype](https://studio3t.com/whats-new/best-practices-uuid-mongodb/)
205
- * for this buffer. You can find a [list of allowed subtypes here](http://api.mongodb.com/python/current/api/bson/binary.html).
205
+ * for this buffer. You can find a [list of allowed subtypes here](https://api.mongodb.com/python/current/api/bson/binary.html).
206
206
  *
207
207
  * ####Example:
208
208
  *
@@ -201,7 +201,7 @@ SchemaDate.prototype.checkRequired = function(value, doc) {
201
201
 
202
202
  // `require('util').inherits()` does **not** copy static properties, and
203
203
  // plugins like mongoose-float use `inherits()` for pre-ES6.
204
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
204
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
205
205
  this.constructor.checkRequired() :
206
206
  SchemaDate.checkRequired();
207
207
  return _checkRequired(value);
@@ -146,7 +146,7 @@ Decimal128.prototype.checkRequired = function checkRequired(value, doc) {
146
146
 
147
147
  // `require('util').inherits()` does **not** copy static properties, and
148
148
  // plugins like mongoose-float use `inherits()` for pre-ES6.
149
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
149
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
150
150
  this.constructor.checkRequired() :
151
151
  Decimal128.checkRequired();
152
152
 
@@ -11,7 +11,6 @@ const SchemaDocumentArrayOptions =
11
11
  require('../options/SchemaDocumentArrayOptions');
12
12
  const SchemaType = require('../schematype');
13
13
  const discriminator = require('../helpers/model/discriminator');
14
- const get = require('../helpers/get');
15
14
  const handleIdOption = require('../helpers/schema/handleIdOption');
16
15
  const util = require('util');
17
16
  const utils = require('../utils');
@@ -68,7 +67,9 @@ function DocumentArrayPath(key, schema, options, schemaOptions) {
68
67
 
69
68
  const parentSchemaType = this;
70
69
  this.$embeddedSchemaType = new SchemaType(key + '.$', {
71
- required: get(this, 'schemaOptions.required', false)
70
+ required: this &&
71
+ this.schemaOptions &&
72
+ this.schemaOptions.required || false
72
73
  });
73
74
  this.$embeddedSchemaType.cast = function(value, doc, init) {
74
75
  return parentSchemaType.cast(value, doc, init)[0];
@@ -173,7 +174,7 @@ DocumentArrayPath.prototype.discriminator = function(name, schema, options) {
173
174
 
174
175
  options = options || {};
175
176
  const tiedValue = utils.isPOJO(options) ? options.value : options;
176
- const clone = get(options, 'clone', true);
177
+ const clone = typeof options.clone === 'boolean' ? options.clone : true;
177
178
 
178
179
  if (schema.instanceOfSchema && clone) {
179
180
  schema = schema.clone();
@@ -228,7 +229,7 @@ DocumentArrayPath.prototype.doValidate = function(array, fn, scope, options) {
228
229
  if (options && options.updateValidator) {
229
230
  return fn();
230
231
  }
231
- if (!array.isMongooseDocumentArray) {
232
+ if (!utils.isMongooseDocumentArray(array)) {
232
233
  array = new MongooseDocumentArray(array, _this.path, scope);
233
234
  }
234
235
 
@@ -398,12 +399,9 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
398
399
  return this.cast([value], doc, init, prev, options);
399
400
  }
400
401
 
401
- if (!(value && value.isMongooseDocumentArray) &&
402
- !options.skipDocumentArrayCast) {
403
- value = new MongooseDocumentArray(value, this.path, doc);
404
- } else if (value && value.isMongooseDocumentArray) {
405
- // We need to create a new array, otherwise change tracking will
406
- // update the old doc (gh-4449)
402
+ // We need to create a new array, otherwise change tracking will
403
+ // update the old doc (gh-4449)
404
+ if (!options.skipDocumentArrayCast || utils.isMongooseDocumentArray(value)) {
407
405
  value = new MongooseDocumentArray(value, this.path, doc);
408
406
  }
409
407
 
@@ -415,7 +413,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
415
413
  value[arrayPathSymbol] = this.path + '.' + options.arrayPathIndex;
416
414
  }
417
415
 
418
- const rawArray = value.isMongooseDocumentArrayProxy ? value.__array : value;
416
+ const rawArray = utils.isMongooseDocumentArray(value) ? value.__array : value;
419
417
 
420
418
  const len = rawArray.length;
421
419
  const initDocumentOptions = { skipId: true, willInit: true };
@@ -170,7 +170,7 @@ SchemaNumber.prototype.checkRequired = function checkRequired(value, doc) {
170
170
 
171
171
  // `require('util').inherits()` does **not** copy static properties, and
172
172
  // plugins like mongoose-float use `inherits()` for pre-ES6.
173
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
173
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
174
174
  this.constructor.checkRequired() :
175
175
  SchemaNumber.checkRequired();
176
176
 
@@ -204,7 +204,7 @@ ObjectId.prototype.checkRequired = function checkRequired(value, doc) {
204
204
 
205
205
  // `require('util').inherits()` does **not** copy static properties, and
206
206
  // plugins like mongoose-float use `inherits()` for pre-ES6.
207
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
207
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
208
208
  this.constructor.checkRequired() :
209
209
  ObjectId.checkRequired();
210
210
 
@@ -281,7 +281,7 @@ function resetId(v) {
281
281
 
282
282
  if (this instanceof Document) {
283
283
  if (v === void 0) {
284
- const _v = new oid;
284
+ const _v = new oid();
285
285
  this.$__._id = _v;
286
286
  return _v;
287
287
  }
@@ -253,7 +253,7 @@ SchemaString.prototype.enum = function() {
253
253
  };
254
254
 
255
255
  /**
256
- * Adds a lowercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
256
+ * Adds a lowercase [setter](https://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
257
257
  *
258
258
  * ####Example:
259
259
  *
@@ -291,7 +291,7 @@ SchemaString.prototype.lowercase = function(shouldApply) {
291
291
  };
292
292
 
293
293
  /**
294
- * Adds an uppercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
294
+ * Adds an uppercase [setter](https://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
295
295
  *
296
296
  * ####Example:
297
297
  *
@@ -327,7 +327,7 @@ SchemaString.prototype.uppercase = function(shouldApply) {
327
327
  };
328
328
 
329
329
  /**
330
- * Adds a trim [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
330
+ * Adds a trim [setter](https://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
331
331
  *
332
332
  * The string value will be [trimmed](https://masteringjs.io/tutorials/fundamentals/trim-string) when set.
333
333
  *
@@ -566,7 +566,7 @@ SchemaString.prototype.checkRequired = function checkRequired(value, doc) {
566
566
 
567
567
  // `require('util').inherits()` does **not** copy static properties, and
568
568
  // plugins like mongoose-float use `inherits()` for pre-ES6.
569
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
569
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
570
570
  this.constructor.checkRequired() :
571
571
  SchemaString.checkRequired();
572
572
 
package/lib/schema.js CHANGED
@@ -75,6 +75,7 @@ let id = 0;
75
75
  * - [selectPopulatedPaths](/docs/guide.html#selectPopulatedPaths): boolean - defaults to `true`
76
76
  * - [skipVersioning](/docs/guide.html#skipVersioning): object - paths to exclude from versioning
77
77
  * - [timestamps](/docs/guide.html#timestamps): object or boolean - defaults to `false`. If true, Mongoose adds `createdAt` and `updatedAt` properties to your schema and manages those properties for you.
78
+ * - [pluginTags](/docs/guide.html#pluginTags): array of strings - defaults to `undefined`. If set and plugin called with `tags` option, will only apply that plugin to schemas with a matching tag.
78
79
  *
79
80
  * ####Options for Nested Schemas:
80
81
  * - `excludeIndexes`: bool - defaults to `false`. If `true`, skip building indexes on this schema's paths.
@@ -85,7 +86,7 @@ let id = 0;
85
86
  *
86
87
  * @param {Object|Schema|Array} [definition] Can be one of: object describing schema paths, or schema to copy, or array of objects and schemas
87
88
  * @param {Object} [options]
88
- * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
89
+ * @inherits NodeJS EventEmitter https://nodejs.org/api/events.html#events_class_events_eventemitter
89
90
  * @event `init`: Emitted after the schema is compiled into a `Model`.
90
91
  * @api public
91
92
  */
@@ -424,7 +425,7 @@ Schema.prototype.pick = function(paths, options) {
424
425
 
425
426
  Schema.prototype.defaultOptions = function(options) {
426
427
  this._userProvidedOptions = options == null ? {} : utils.clone(options);
427
- const baseOptions = get(this, 'base.options', {});
428
+ const baseOptions = this.base && this.base.options || {};
428
429
 
429
430
  const strict = 'strict' in baseOptions ? baseOptions.strict : true;
430
431
  options = utils.options({
@@ -518,7 +519,7 @@ Schema.prototype.add = function add(obj, prefix) {
518
519
  if (key === '_id' && val === false) {
519
520
  continue;
520
521
  }
521
- if (val instanceof VirtualType || get(val, 'constructor.name', null) === 'VirtualType') {
522
+ if (val instanceof VirtualType || (val.constructor && val.constructor.name || null) === 'VirtualType') {
522
523
  this.virtual(val);
523
524
  continue;
524
525
  }
@@ -1018,6 +1019,10 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1018
1019
  ? cast[options.typeKey]
1019
1020
  : cast;
1020
1021
 
1022
+ if (Array.isArray(type)) {
1023
+ return new MongooseTypes.Array(path, this.interpretAsType(path, type, options), obj);
1024
+ }
1025
+
1021
1026
  name = typeof type === 'string'
1022
1027
  ? type
1023
1028
  : type.schemaName || utils.getFunctionName(type);
@@ -1035,7 +1040,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1035
1040
  if (!MongooseTypes.hasOwnProperty(name)) {
1036
1041
  throw new TypeError('Invalid schema configuration: ' +
1037
1042
  `\`${name}\` is not a valid type within the array \`${path}\`.` +
1038
- 'See http://bit.ly/mongoose-schematypes for a list of valid schema types.');
1043
+ 'See https://bit.ly/mongoose-schematypes for a list of valid schema types.');
1039
1044
  }
1040
1045
  }
1041
1046
 
@@ -1075,7 +1080,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1075
1080
  if (MongooseTypes[name] == null) {
1076
1081
  throw new TypeError(`Invalid schema configuration: \`${name}\` is not ` +
1077
1082
  `a valid type at path \`${path}\`. See ` +
1078
- 'http://bit.ly/mongoose-schematypes for a list of valid schema types.');
1083
+ 'https://bit.ly/mongoose-schematypes for a list of valid schema types.');
1079
1084
  }
1080
1085
 
1081
1086
  const schemaType = new MongooseTypes[name](path, obj);
@@ -1470,8 +1475,8 @@ Schema.prototype.pre = function(name) {
1470
1475
  * @param {Boolean} [options.document] If `name` is a hook for both document and query middleware, set to `true` to run on document middleware.
1471
1476
  * @param {Boolean} [options.query] If `name` is a hook for both document and query middleware, set to `true` to run on query middleware.
1472
1477
  * @param {Function} fn callback
1473
- * @see middleware http://mongoosejs.com/docs/middleware.html
1474
- * @see kareem http://npmjs.org/package/kareem
1478
+ * @see middleware https://mongoosejs.com/docs/middleware.html
1479
+ * @see kareem https://npmjs.org/package/kareem
1475
1480
  * @api public
1476
1481
  */
1477
1482
 
@@ -1618,7 +1623,7 @@ Schema.prototype.static = function(name, fn) {
1618
1623
  * schema.index({ first: 1, last: -1 })
1619
1624
  *
1620
1625
  * @param {Object} fields
1621
- * @param {Object} [options] Options to pass to [MongoDB driver's `createIndex()` function](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#createIndex)
1626
+ * @param {Object} [options] Options to pass to [MongoDB driver's `createIndex()` function](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#createIndex)
1622
1627
  * @param {String | number} [options.expires=null] Mongoose-specific syntactic sugar, uses [ms](https://www.npmjs.com/package/ms) to convert `expires` option into seconds for the `expireAfterSeconds` in the above link.
1623
1628
  * @api public
1624
1629
  */