mongoose 6.2.2 → 6.2.5

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/model.js CHANGED
@@ -43,6 +43,11 @@ const immediate = require('./helpers/immediate');
43
43
  const internalToObjectOptions = require('./options').internalToObjectOptions;
44
44
  const isDefaultIdIndex = require('./helpers/indexes/isDefaultIdIndex');
45
45
  const isIndexEqual = require('./helpers/indexes/isIndexEqual');
46
+ const {
47
+ getRelatedDBIndexes,
48
+ getRelatedSchemaIndexes
49
+ } = require('./helpers/indexes/getRelatedIndexes');
50
+ const decorateDiscriminatorIndexOptions = require('./helpers/indexes/decorateDiscriminatorIndexOptions');
46
51
  const isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
47
52
  const leanPopulateMap = require('./helpers/populate/leanPopulateMap');
48
53
  const modifiedPaths = require('./helpers/update/modifiedPaths');
@@ -1471,8 +1476,7 @@ Model.diffIndexes = function diffIndexes(options, callback) {
1471
1476
 
1472
1477
  for (const schemaIndex of schemaIndexes) {
1473
1478
  const key = schemaIndex[0];
1474
- const options = _decorateDiscriminatorIndexOptions(this,
1475
- utils.clone(schemaIndex[1]));
1479
+ const options = decorateDiscriminatorIndexOptions(this.schema, utils.clone(schemaIndex[1]));
1476
1480
  if (isIndexEqual(key, options, index)) {
1477
1481
  found = true;
1478
1482
  }
@@ -1485,10 +1489,9 @@ Model.diffIndexes = function diffIndexes(options, callback) {
1485
1489
  // Iterate through the indexes created on the schema and
1486
1490
  // compare against the indexes in mongodb.
1487
1491
  for (const schemaIndex of schemaIndexes) {
1488
- const key = schemaIndex[0];
1489
1492
  let found = false;
1490
- const options = _decorateDiscriminatorIndexOptions(this,
1491
- utils.clone(schemaIndex[1]));
1493
+ const key = schemaIndex[0];
1494
+ const options = decorateDiscriminatorIndexOptions(this.schema, utils.clone(schemaIndex[1]));
1492
1495
  for (const index of indexes) {
1493
1496
  if (isDefaultIdIndex(index)) {
1494
1497
  continue;
@@ -1525,32 +1528,33 @@ Model.cleanIndexes = function cleanIndexes(callback) {
1525
1528
  return this.db.base._promiseOrCallback(callback, cb => {
1526
1529
  const collection = this.$__collection;
1527
1530
 
1528
- this.listIndexes((err, indexes) => {
1531
+ this.listIndexes((err, dbIndexes) => {
1529
1532
  if (err != null) {
1530
1533
  return cb(err);
1531
1534
  }
1532
1535
 
1533
- const schemaIndexes = this.schema.indexes();
1536
+ dbIndexes = getRelatedDBIndexes(this, dbIndexes);
1537
+ const schemaIndexes = getRelatedSchemaIndexes(this, this.schema.indexes());
1538
+
1534
1539
  const toDrop = [];
1535
1540
 
1536
- for (const index of indexes) {
1541
+ for (const dbIndex of dbIndexes) {
1537
1542
  let found = false;
1538
1543
  // Never try to drop `_id` index, MongoDB server doesn't allow it
1539
- if (isDefaultIdIndex(index)) {
1544
+ if (isDefaultIdIndex(dbIndex)) {
1540
1545
  continue;
1541
1546
  }
1542
1547
 
1543
- for (const schemaIndex of schemaIndexes) {
1544
- const key = schemaIndex[0];
1545
- const options = _decorateDiscriminatorIndexOptions(this,
1546
- utils.clone(schemaIndex[1]));
1547
- if (isIndexEqual(key, options, index)) {
1548
+ for (const [schemaIndexKeysObject, schemaIndexOptions] of schemaIndexes) {
1549
+ const options = decorateDiscriminatorIndexOptions(this.schema, utils.clone(schemaIndexOptions));
1550
+
1551
+ if (isIndexEqual(schemaIndexKeysObject, options, dbIndex)) {
1548
1552
  found = true;
1549
1553
  }
1550
1554
  }
1551
1555
 
1552
1556
  if (!found) {
1553
- toDrop.push(index.name);
1557
+ toDrop.push(dbIndex.name);
1554
1558
  }
1555
1559
  }
1556
1560
 
@@ -1729,7 +1733,17 @@ function _ensureIndexes(model, options, callback) {
1729
1733
  const baseSchema = model.schema._baseSchema;
1730
1734
  const baseSchemaIndexes = baseSchema ? baseSchema.indexes() : [];
1731
1735
 
1732
- const create = function() {
1736
+ immediate(function() {
1737
+ // If buffering is off, do this manually.
1738
+ if (options._automatic && !model.collection.collection) {
1739
+ model.collection.addQueue(create, []);
1740
+ } else {
1741
+ create();
1742
+ }
1743
+ });
1744
+
1745
+
1746
+ function create() {
1733
1747
  if (options._automatic) {
1734
1748
  if (model.schema.options.autoIndex === false ||
1735
1749
  (model.schema.options.autoIndex == null && model.db.config.autoIndex === false)) {
@@ -1758,7 +1772,7 @@ function _ensureIndexes(model, options, callback) {
1758
1772
  }
1759
1773
  }
1760
1774
  delete indexOptions._autoIndex;
1761
- _decorateDiscriminatorIndexOptions(model, indexOptions);
1775
+ decorateDiscriminatorIndexOptions(model.schema, indexOptions);
1762
1776
  applyWriteConcern(model.schema, indexOptions);
1763
1777
 
1764
1778
  indexSingleStart(indexFields, options);
@@ -1784,34 +1798,7 @@ function _ensureIndexes(model, options, callback) {
1784
1798
  }
1785
1799
  create();
1786
1800
  }));
1787
- };
1788
-
1789
- immediate(function() {
1790
- // If buffering is off, do this manually.
1791
- if (options._automatic && !model.collection.collection) {
1792
- model.collection.addQueue(create, []);
1793
- } else {
1794
- create();
1795
- }
1796
- });
1797
- }
1798
-
1799
- function _decorateDiscriminatorIndexOptions(model, indexOptions) {
1800
- // If the model is a discriminator and it has a unique index, add a
1801
- // partialFilterExpression by default so the unique index will only apply
1802
- // to that discriminator.
1803
- if (model.baseModelName != null &&
1804
- !('partialFilterExpression' in indexOptions) &&
1805
- !('sparse' in indexOptions)) {
1806
- const value = (
1807
- model.schema.discriminatorMapping &&
1808
- model.schema.discriminatorMapping.value
1809
- ) || model.modelName;
1810
- const discriminatorKey = model.schema.options.discriminatorKey;
1811
-
1812
- indexOptions.partialFilterExpression = { [discriminatorKey]: value };
1813
- }
1814
- return indexOptions;
1801
+ }
1815
1802
  }
1816
1803
 
1817
1804
  /**
@@ -2494,7 +2481,7 @@ Model.$where = function $where() {
2494
2481
  * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
2495
2482
  * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
2496
2483
  * - `setDefaultsOnInsert`: `true` by default. If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created.
2497
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
2484
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2498
2485
  * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2499
2486
  *
2500
2487
  * ####Examples:
@@ -2630,7 +2617,7 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
2630
2617
  * - `setDefaultsOnInsert`: `true` by default. If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created.
2631
2618
  * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
2632
2619
  * - `select`: sets the document fields to return
2633
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
2620
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2634
2621
  * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2635
2622
  *
2636
2623
  * ####Examples:
@@ -2731,7 +2718,7 @@ Model.findByIdAndUpdate = function(id, update, options, callback) {
2731
2718
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
2732
2719
  * - `select`: sets the document fields to return, ex. `{ projection: { _id: 0 } }`
2733
2720
  * - `projection`: equivalent to `select`
2734
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
2721
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2735
2722
  * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2736
2723
  *
2737
2724
  * ####Examples:
@@ -2844,7 +2831,7 @@ Model.findByIdAndDelete = function(id, options, callback) {
2844
2831
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
2845
2832
  * - `select`: sets the document fields to return
2846
2833
  * - `projection`: like select, it determines which fields to return, ex. `{ projection: { _id: 0 } }`
2847
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
2834
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2848
2835
  * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2849
2836
  *
2850
2837
  * ####Examples:
@@ -2921,7 +2908,7 @@ Model.findOneAndReplace = function(filter, replacement, options, callback) {
2921
2908
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
2922
2909
  * - `select`: sets the document fields to return
2923
2910
  * - `projection`: like select, it determines which fields to return, ex. `{ projection: { _id: 0 } }`
2924
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
2911
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
2925
2912
  * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
2926
2913
  *
2927
2914
  * ####Examples:
@@ -2999,7 +2986,7 @@ Model.findOneAndRemove = function(conditions, options, callback) {
2999
2986
  *
3000
2987
  * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
3001
2988
  * - `select`: sets the document fields to return
3002
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
2989
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3003
2990
  * - `strict`: overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) for this update
3004
2991
  *
3005
2992
  * ####Examples:
@@ -3529,9 +3516,7 @@ function _setIsNew(doc, val) {
3529
3516
  * },
3530
3517
  * {
3531
3518
  * deleteOne: {
3532
- * {
3533
- * filter: { name: 'Eddard Stark' }
3534
- * }
3519
+ * filter: { name: 'Eddard Stark' }
3535
3520
  * }
3536
3521
  * }
3537
3522
  * ]).then(res => {
@@ -4406,6 +4391,7 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) {
4406
4391
  * @param {Document|Array} docs Either a single document or array of documents to populate.
4407
4392
  * @param {Object|String} options Either the paths to populate or an object specifying all parameters
4408
4393
  * @param {string} [options.path=null] The path to populate.
4394
+ * @param {string|PopulateOptions} [options.populate=null] Recursively populate paths in the populated documents. See [deep populate docs](/docs/populate.html#deep-populate).
4409
4395
  * @param {boolean} [options.retainNullValues=false] By default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
4410
4396
  * @param {boolean} [options.getters=false] If true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](/docs/schematypes.html#schematype-options).
4411
4397
  * @param {boolean} [options.clone=false] When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
@@ -4766,7 +4752,7 @@ function _assign(model, vals, mod, assignmentOpts) {
4766
4752
  }
4767
4753
  // flag each as result of population
4768
4754
  if (!lean) {
4769
- val.$__.wasPopulated = true;
4755
+ val.$__.wasPopulated = val.$__.wasPopulated || true;
4770
4756
  }
4771
4757
  }
4772
4758
  }
package/lib/query.js CHANGED
@@ -2980,7 +2980,7 @@ Query.prototype._remove = wrapThunk(function(callback) {
2980
2980
 
2981
2981
  callback = _wrapThunkCallback(this, callback);
2982
2982
 
2983
- return Query.base.remove.call(this, helpers.handleDeleteWriteOpResult(callback));
2983
+ return Query.base.remove.call(this, callback);
2984
2984
  });
2985
2985
 
2986
2986
  /**
@@ -3066,7 +3066,7 @@ Query.prototype._deleteOne = wrapThunk(function(callback) {
3066
3066
 
3067
3067
  callback = _wrapThunkCallback(this, callback);
3068
3068
 
3069
- return Query.base.deleteOne.call(this, helpers.handleDeleteWriteOpResult(callback));
3069
+ return Query.base.deleteOne.call(this, callback);
3070
3070
  });
3071
3071
 
3072
3072
  /**
@@ -3152,7 +3152,7 @@ Query.prototype._deleteMany = wrapThunk(function(callback) {
3152
3152
 
3153
3153
  callback = _wrapThunkCallback(this, callback);
3154
3154
 
3155
- return Query.base.deleteMany.call(this, helpers.handleDeleteWriteOpResult(callback));
3155
+ return Query.base.deleteMany.call(this, callback);
3156
3156
  });
3157
3157
 
3158
3158
  /*!
@@ -3244,7 +3244,7 @@ function prepareDiscriminatorCriteria(query) {
3244
3244
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
3245
3245
  * - `runValidators`: if true, runs [update validators](/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema.
3246
3246
  * - `setDefaultsOnInsert`: `true` by default. If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created.
3247
- * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3247
+ * - `rawResult`: if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3248
3248
  *
3249
3249
  * ####Callback Signature
3250
3250
  * function(error, doc) {
@@ -3269,7 +3269,7 @@ function prepareDiscriminatorCriteria(query) {
3269
3269
  * @param {Object|Query} [filter]
3270
3270
  * @param {Object} [doc]
3271
3271
  * @param {Object} [options]
3272
- * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3272
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3273
3273
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
3274
3274
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
3275
3275
  * @param {Boolean} [options.multipleCastError] by default, mongoose only returns the first error that occurred in casting the query. Turn on this option to aggregate all the cast errors.
@@ -3386,7 +3386,7 @@ Query.prototype._findOneAndUpdate = wrapThunk(function(callback) {
3386
3386
  *
3387
3387
  * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
3388
3388
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
3389
- * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3389
+ * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3390
3390
  *
3391
3391
  * ####Callback Signature
3392
3392
  * function(error, doc) {
@@ -3408,7 +3408,7 @@ Query.prototype._findOneAndUpdate = wrapThunk(function(callback) {
3408
3408
  * @instance
3409
3409
  * @param {Object} [conditions]
3410
3410
  * @param {Object} [options]
3411
- * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3411
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3412
3412
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
3413
3413
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
3414
3414
  * @param {Function} [callback] optional params are (error, document)
@@ -3473,7 +3473,7 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
3473
3473
  *
3474
3474
  * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
3475
3475
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
3476
- * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3476
+ * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3477
3477
  *
3478
3478
  * ####Callback Signature
3479
3479
  * function(error, doc) {
@@ -3494,7 +3494,7 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
3494
3494
  * @memberOf Query
3495
3495
  * @param {Object} [conditions]
3496
3496
  * @param {Object} [options]
3497
- * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3497
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3498
3498
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
3499
3499
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
3500
3500
  * @param {Function} [callback] optional params are (error, document)
@@ -3592,7 +3592,7 @@ Query.prototype._findOneAndDelete = wrapThunk(function(callback) {
3592
3592
  *
3593
3593
  * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
3594
3594
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
3595
- * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3595
+ * - `rawResult`: if true, resolves to the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3596
3596
  *
3597
3597
  * ####Callback Signature
3598
3598
  * function(error, doc) {
@@ -3614,7 +3614,7 @@ Query.prototype._findOneAndDelete = wrapThunk(function(callback) {
3614
3614
  * @param {Object} [filter]
3615
3615
  * @param {Object} [replacement]
3616
3616
  * @param {Object} [options]
3617
- * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify)
3617
+ * @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.3/interfaces/ModifyResult.html)
3618
3618
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](/docs/transactions.html).
3619
3619
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
3620
3620
  * @param {Boolean} [options.new=false] By default, `findOneAndUpdate()` returns the document as it was **before** `update` was applied. If you set `new: true`, `findOneAndUpdate()` will instead give you the object after `update` was applied.
@@ -308,23 +308,3 @@ function makeLean(val) {
308
308
  option.options.lean = val;
309
309
  };
310
310
  }
311
-
312
- /*!
313
- * Handle the `WriteOpResult` from the server
314
- */
315
-
316
- exports.handleDeleteWriteOpResult = function handleDeleteWriteOpResult(callback) {
317
- return function _handleDeleteWriteOpResult(error, res) {
318
- if (error) {
319
- return callback(error);
320
- }
321
- const mongooseResult = Object.assign({}, res.result);
322
- if ((res && res.result && res.result.n || null) != null) {
323
- mongooseResult.deletedCount = res.result.n;
324
- }
325
- if (res.deletedCount != null) {
326
- mongooseResult.deletedCount = res.deletedCount;
327
- }
328
- return callback(null, mongooseResult);
329
- };
330
- };
@@ -239,7 +239,7 @@ SubdocumentPath.prototype.doValidate = function(value, fn, scope, options) {
239
239
  const Constructor = getConstructor(this.caster, value);
240
240
 
241
241
  if (value && !(value instanceof Constructor)) {
242
- value = new Constructor(value, null, scope);
242
+ value = new Constructor(value, null, (scope != null && scope.$__ != null) ? scope : null);
243
243
  }
244
244
 
245
245
  if (options && options.skipSchemaValidators) {
@@ -646,6 +646,7 @@ handle.$gte =
646
646
  handle.$lt =
647
647
  handle.$lte =
648
648
  handle.$ne =
649
+ handle.$not =
649
650
  handle.$regex = SchemaArray.prototype.castForQuery;
650
651
 
651
652
  // `$in` is special because you can also include an empty array in the query
@@ -365,6 +365,9 @@ DocumentArrayPath.prototype.getDefault = function(scope) {
365
365
  return ret;
366
366
  };
367
367
 
368
+ const _toObjectOptions = Object.freeze({ transform: false, virtuals: false });
369
+ const initDocumentOptions = Object.freeze({ skipId: true, willInit: true });
370
+
368
371
  /**
369
372
  * Casts contents
370
373
  *
@@ -384,7 +387,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
384
387
 
385
388
  let selected;
386
389
  let subdoc;
387
- const _opts = { transform: false, virtuals: false };
390
+
388
391
  options = options || {};
389
392
 
390
393
  if (!Array.isArray(value)) {
@@ -414,9 +417,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
414
417
  }
415
418
 
416
419
  const rawArray = utils.isMongooseDocumentArray(value) ? value.__array : value;
417
-
418
420
  const len = rawArray.length;
419
- const initDocumentOptions = { skipId: true, willInit: true };
420
421
 
421
422
  for (let i = 0; i < len; ++i) {
422
423
  if (!rawArray[i]) {
@@ -464,7 +465,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
464
465
  subdoc = prev.id(rawArray[i]._id);
465
466
  }
466
467
 
467
- if (prev && subdoc && utils.deepEqual(subdoc.toObject(_opts), rawArray[i])) {
468
+ if (prev && subdoc && utils.deepEqual(subdoc.toObject(_toObjectOptions), rawArray[i])) {
468
469
  // handle resetting doc with existing id and same data
469
470
  subdoc.set(rawArray[i]);
470
471
  // if set() is hooked it will have no return value
package/lib/schema.js CHANGED
@@ -1019,6 +1019,10 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1019
1019
  ? cast[options.typeKey]
1020
1020
  : cast;
1021
1021
 
1022
+ if (Array.isArray(type)) {
1023
+ return new MongooseTypes.Array(path, this.interpretAsType(path, type, options), obj);
1024
+ }
1025
+
1022
1026
  name = typeof type === 'string'
1023
1027
  ? type
1024
1028
  : type.schemaName || utils.getFunctionName(type);
package/lib/schematype.js CHANGED
@@ -10,6 +10,7 @@ const $exists = require('./schema/operators/exists');
10
10
  const $type = require('./schema/operators/type');
11
11
  const handleImmutable = require('./helpers/schematype/handleImmutable');
12
12
  const isAsyncFunction = require('./helpers/isAsyncFunction');
13
+ const isSimpleValidator = require('./helpers/isSimpleValidator');
13
14
  const immediate = require('./helpers/immediate');
14
15
  const schemaTypeSymbol = require('./helpers/symbols').schemaTypeSymbol;
15
16
  const utils = require('./utils');
@@ -886,7 +887,7 @@ SchemaType.prototype.validate = function(obj, message, type) {
886
887
  properties = { validator: obj, message: message };
887
888
  properties.type = type || 'user defined';
888
889
  } else if (message instanceof Object && !type) {
889
- properties = utils.clone(message);
890
+ properties = isSimpleValidator(message) ? Object.assign({}, message) : utils.clone(message);
890
891
  if (!properties.message) {
891
892
  properties.message = properties.msg;
892
893
  }
@@ -914,8 +915,8 @@ SchemaType.prototype.validate = function(obj, message, type) {
914
915
  arg = arguments[i];
915
916
  if (!utils.isPOJO(arg)) {
916
917
  const msg = 'Invalid validator. Received (' + typeof arg + ') '
917
- + arg
918
- + '. See https://mongoosejs.com/docs/api.html#schematype_SchemaType-validate';
918
+ + arg
919
+ + '. See https://mongoosejs.com/docs/api.html#schematype_SchemaType-validate';
919
920
 
920
921
  throw new Error(msg);
921
922
  }
@@ -1242,7 +1243,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
1242
1243
 
1243
1244
  // Avoid non-object `validators`
1244
1245
  const validators = this.validators.
1245
- filter(v => v != null && typeof v === 'object');
1246
+ filter(v => typeof v === 'object' && v !== null);
1246
1247
 
1247
1248
  let count = validators.length;
1248
1249
 
@@ -1250,31 +1251,31 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
1250
1251
  return fn(null);
1251
1252
  }
1252
1253
 
1253
- const _this = this;
1254
- validators.forEach(function(v) {
1254
+ for (let i = 0, len = validators.length; i < len; ++i) {
1255
1255
  if (err) {
1256
- return;
1256
+ break;
1257
1257
  }
1258
1258
 
1259
+ const v = validators[i];
1259
1260
  const validator = v.validator;
1260
1261
  let ok;
1261
1262
 
1262
- const validatorProperties = utils.clone(v);
1263
+ const validatorProperties = isSimpleValidator(v) ? Object.assign({}, v) : utils.clone(v);
1263
1264
  validatorProperties.path = options && options.path ? options.path : path;
1264
1265
  validatorProperties.value = value;
1265
1266
 
1266
1267
  if (validator instanceof RegExp) {
1267
1268
  validate(validator.test(value), validatorProperties);
1268
- return;
1269
+ continue;
1269
1270
  }
1270
1271
 
1271
1272
  if (typeof validator !== 'function') {
1272
- return;
1273
+ continue;
1273
1274
  }
1274
1275
 
1275
- if (value === undefined && validator !== _this.requiredValidator) {
1276
+ if (value === undefined && validator !== this.requiredValidator) {
1276
1277
  validate(true, validatorProperties);
1277
- return;
1278
+ continue;
1278
1279
  }
1279
1280
 
1280
1281
  try {
@@ -1303,8 +1304,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
1303
1304
  } else {
1304
1305
  validate(ok, validatorProperties);
1305
1306
  }
1306
-
1307
- });
1307
+ }
1308
1308
 
1309
1309
  function validate(ok, validatorProperties) {
1310
1310
  if (err) {
@@ -1374,12 +1374,12 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
1374
1374
 
1375
1375
  const v = validators[i];
1376
1376
 
1377
- if (v == null || typeof v !== 'object') {
1377
+ if (v === null || typeof v !== 'object') {
1378
1378
  continue;
1379
1379
  }
1380
1380
 
1381
1381
  const validator = v.validator;
1382
- const validatorProperties = utils.clone(v);
1382
+ const validatorProperties = isSimpleValidator(v) ? Object.assign({}, v) : utils.clone(v);
1383
1383
  validatorProperties.path = options && options.path ? options.path : path;
1384
1384
  validatorProperties.value = value;
1385
1385
  let ok = false;
@@ -1454,8 +1454,8 @@ SchemaType._isRef = function(self, value, doc, init) {
1454
1454
  return true;
1455
1455
  }
1456
1456
  if (!Buffer.isBuffer(value) && // buffers are objects too
1457
- value._bsontype !== 'Binary' // raw binary value from the db
1458
- && utils.isObject(value) // might have deselected _id in population query
1457
+ value._bsontype !== 'Binary' // raw binary value from the db
1458
+ && utils.isObject(value) // might have deselected _id in population query
1459
1459
  ) {
1460
1460
  return true;
1461
1461
  }
@@ -1476,7 +1476,7 @@ SchemaType.prototype._castRef = function _castRef(value, doc, init) {
1476
1476
  }
1477
1477
 
1478
1478
  if (value.$__ != null) {
1479
- value.$__.wasPopulated = true;
1479
+ value.$__.wasPopulated = value.$__.wasPopulated || true;
1480
1480
  return value;
1481
1481
  }
1482
1482
 
@@ -1496,10 +1496,10 @@ SchemaType.prototype._castRef = function _castRef(value, doc, init) {
1496
1496
  const pop = owner.$populated(path, true);
1497
1497
  let ret = value;
1498
1498
  if (!doc.$__.populated ||
1499
- !doc.$__.populated[path] ||
1500
- !doc.$__.populated[path].options ||
1501
- !doc.$__.populated[path].options.options ||
1502
- !doc.$__.populated[path].options.options.lean) {
1499
+ !doc.$__.populated[path] ||
1500
+ !doc.$__.populated[path].options ||
1501
+ !doc.$__.populated[path].options.options ||
1502
+ !doc.$__.populated[path].options.options.lean) {
1503
1503
  ret = new pop.options[populateModelSymbol](value);
1504
1504
  ret.$__.wasPopulated = true;
1505
1505
  }
@@ -31,7 +31,7 @@ function ArraySubdocument(obj, parentArr, skipId, fields, index) {
31
31
  this.$setIndex(index);
32
32
  this.$__parent = this[documentArrayParent];
33
33
 
34
- Subdocument.call(this, obj, fields, this[documentArrayParent], void 0, { isNew: true });
34
+ Subdocument.call(this, obj, fields, this[documentArrayParent], skipId, { isNew: true });
35
35
  }
36
36
 
37
37
  /*!
package/lib/types/map.js CHANGED
@@ -82,7 +82,7 @@ class MongooseMap extends Map {
82
82
  if (value.$__ == null) {
83
83
  value = new populated.options[populateModelSymbol](value);
84
84
  }
85
- value.$__.wasPopulated = true;
85
+ value.$__.wasPopulated = { value: populated.value };
86
86
  } else {
87
87
  try {
88
88
  value = this.$__schemaType.
package/lib/utils.js CHANGED
@@ -70,7 +70,7 @@ exports.deepEqual = function deepEqual(a, b) {
70
70
  return true;
71
71
  }
72
72
 
73
- if (typeof a !== 'object' && typeof b !== 'object') {
73
+ if (typeof a !== 'object' || typeof b !== 'object') {
74
74
  return a === b;
75
75
  }
76
76
 
@@ -102,7 +102,10 @@ exports.deepEqual = function deepEqual(a, b) {
102
102
  return false;
103
103
  }
104
104
 
105
- if (a instanceof Map && b instanceof Map) {
105
+ if (a instanceof Map || b instanceof Map) {
106
+ if (!(a instanceof Map) || !(b instanceof Map)) {
107
+ return false;
108
+ }
106
109
  return deepEqual(Array.from(a.keys()), Array.from(b.keys())) &&
107
110
  deepEqual(Array.from(a.values()), Array.from(b.values()));
108
111
  }
@@ -116,7 +119,10 @@ exports.deepEqual = function deepEqual(a, b) {
116
119
  return exports.buffer.areEqual(a, b);
117
120
  }
118
121
 
119
- if (Array.isArray(a) && Array.isArray(b)) {
122
+ if (Array.isArray(a) || Array.isArray(b)) {
123
+ if (!Array.isArray(a) || !Array.isArray(b)) {
124
+ return false;
125
+ }
120
126
  const len = a.length;
121
127
  if (len !== b.length) {
122
128
  return false;