mongoose 6.6.0 → 6.6.2

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/.eslintrc.json CHANGED
@@ -25,6 +25,7 @@
25
25
  "rules": {
26
26
  "@typescript-eslint/triple-slash-reference": "off",
27
27
  "@typescript-eslint/no-non-null-assertion": "off",
28
+ "@typescript-eslint/no-empty-function": "off",
28
29
  "spaced-comment": [
29
30
  "error",
30
31
  "always",
package/lib/aggregate.js CHANGED
@@ -126,7 +126,7 @@ Aggregate.prototype.model = function(model) {
126
126
  /**
127
127
  * Appends new operators to this aggregate pipeline
128
128
  *
129
- * #### Examples:
129
+ * #### Example:
130
130
  *
131
131
  * aggregate.append({ $project: { field: 1 }}, { $limit: 2 });
132
132
  *
@@ -157,7 +157,7 @@ Aggregate.prototype.append = function() {
157
157
  * Appends a new $addFields operator to this aggregate pipeline.
158
158
  * Requires MongoDB v3.4+ to work
159
159
  *
160
- * #### Examples:
160
+ * #### Example:
161
161
  *
162
162
  * // adding new fields based on existing fields
163
163
  * aggregate.addFields({
@@ -188,7 +188,7 @@ Aggregate.prototype.addFields = function(arg) {
188
188
  *
189
189
  * Mongoose query [selection syntax](#query_Query-select) is also supported.
190
190
  *
191
- * #### Examples:
191
+ * #### Example:
192
192
  *
193
193
  * // include a, include b, exclude _id
194
194
  * aggregate.project("a b -_id");
@@ -243,7 +243,7 @@ Aggregate.prototype.project = function(arg) {
243
243
  /**
244
244
  * Appends a new custom $group operator to this aggregate pipeline.
245
245
  *
246
- * #### Examples:
246
+ * #### Example:
247
247
  *
248
248
  * aggregate.group({ _id: "$department" });
249
249
  *
@@ -259,7 +259,7 @@ Aggregate.prototype.project = function(arg) {
259
259
  /**
260
260
  * Appends a new custom $match operator to this aggregate pipeline.
261
261
  *
262
- * #### Examples:
262
+ * #### Example:
263
263
  *
264
264
  * aggregate.match({ department: { $in: [ "sales", "engineering" ] } });
265
265
  *
@@ -275,7 +275,7 @@ Aggregate.prototype.project = function(arg) {
275
275
  /**
276
276
  * Appends a new $skip operator to this aggregate pipeline.
277
277
  *
278
- * #### Examples:
278
+ * #### Example:
279
279
  *
280
280
  * aggregate.skip(10);
281
281
  *
@@ -291,7 +291,7 @@ Aggregate.prototype.project = function(arg) {
291
291
  /**
292
292
  * Appends a new $limit operator to this aggregate pipeline.
293
293
  *
294
- * #### Examples:
294
+ * #### Example:
295
295
  *
296
296
  * aggregate.limit(10);
297
297
  *
@@ -308,7 +308,7 @@ Aggregate.prototype.project = function(arg) {
308
308
  /**
309
309
  * Appends a new $densify operator to this aggregate pipeline.
310
310
  *
311
- * #### Examples:
311
+ * #### Example:
312
312
  *
313
313
  * aggregate.densify({
314
314
  * field: 'timestamp',
@@ -335,7 +335,7 @@ Aggregate.prototype.project = function(arg) {
335
335
  *
336
336
  * **MUST** be used as the first operator in the pipeline.
337
337
  *
338
- * #### Examples:
338
+ * #### Example:
339
339
  *
340
340
  * aggregate.near({
341
341
  * near: [40.724, -73.997],
@@ -380,7 +380,7 @@ Aggregate.prototype.near = function(arg) {
380
380
  * Note that the `$unwind` operator requires the path name to start with '$'.
381
381
  * Mongoose will prepend '$' if the specified field doesn't start '$'.
382
382
  *
383
- * #### Examples:
383
+ * #### Example:
384
384
  *
385
385
  * aggregate.unwind("tags");
386
386
  * aggregate.unwind("a", "b", "c");
@@ -419,7 +419,7 @@ Aggregate.prototype.unwind = function() {
419
419
  * If you are passing in a string Mongoose will prepend '$' if the specified field doesn't start '$'.
420
420
  * If you are passing in an object the strings in your expression will not be altered.
421
421
  *
422
- * #### Examples:
422
+ * #### Example:
423
423
  *
424
424
  * aggregate.replaceRoot("user");
425
425
  *
@@ -450,7 +450,7 @@ Aggregate.prototype.replaceRoot = function(newRoot) {
450
450
  /**
451
451
  * Appends a new $count operator to this aggregate pipeline.
452
452
  *
453
- * #### Examples:
453
+ * #### Example:
454
454
  *
455
455
  * aggregate.count("userCount");
456
456
  *
@@ -471,7 +471,7 @@ Aggregate.prototype.count = function(fieldName) {
471
471
  * Note that the `$sortByCount` operator requires the new root to start with '$'.
472
472
  * Mongoose will prepend '$' if the specified field name doesn't start with '$'.
473
473
  *
474
- * #### Examples:
474
+ * #### Example:
475
475
  *
476
476
  * aggregate.sortByCount('users');
477
477
  * aggregate.sortByCount({ $mergeObjects: [ "$employee", "$business" ] })
@@ -498,7 +498,7 @@ Aggregate.prototype.sortByCount = function(arg) {
498
498
  /**
499
499
  * Appends new custom $lookup operator to this aggregate pipeline.
500
500
  *
501
- * #### Examples:
501
+ * #### Example:
502
502
  *
503
503
  * aggregate.lookup({ from: 'users', localField: 'userId', foreignField: '_id', as: 'users' });
504
504
  *
@@ -517,7 +517,7 @@ Aggregate.prototype.lookup = function(options) {
517
517
  *
518
518
  * Note that graphLookup can only consume at most 100MB of memory, and does not allow disk use even if `{ allowDiskUse: true }` is specified.
519
519
  *
520
- * #### Examples:
520
+ * #### Example:
521
521
  *
522
522
  * // Suppose we have a collection of courses, where a document might look like `{ _id: 0, name: 'Calculus', prerequisite: 'Trigonometry'}` and `{ _id: 0, name: 'Trigonometry', prerequisite: 'Algebra' }`
523
523
  * aggregate.graphLookup({ from: 'courses', startWith: '$prerequisite', connectFromField: 'prerequisite', connectToField: 'name', as: 'prerequisites', maxDepth: 3 }) // this will recursively search the 'courses' collection up to 3 prerequisites
@@ -551,7 +551,7 @@ Aggregate.prototype.graphLookup = function(options) {
551
551
  /**
552
552
  * Appends new custom $sample operator to this aggregate pipeline.
553
553
  *
554
- * #### Examples:
554
+ * #### Example:
555
555
  *
556
556
  * aggregate.sample(3); // Add a pipeline that picks 3 random documents
557
557
  *
@@ -572,7 +572,7 @@ Aggregate.prototype.sample = function(size) {
572
572
  *
573
573
  * If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.
574
574
  *
575
- * #### Examples:
575
+ * #### Example:
576
576
  *
577
577
  * // these are equivalent
578
578
  * aggregate.sort({ field: 'asc', test: -1 });
@@ -620,7 +620,7 @@ Aggregate.prototype.sort = function(arg) {
620
620
  /**
621
621
  * Appends new $unionWith operator to this aggregate pipeline.
622
622
  *
623
- * #### Examples:
623
+ * #### Example:
624
624
  *
625
625
  * aggregate.unionWith({ coll: 'users', pipeline: [ { $match: { _id: 1 } } ] });
626
626
  *
package/lib/document.js CHANGED
@@ -851,11 +851,12 @@ Document.prototype.update = function update() {
851
851
 
852
852
  Document.prototype.updateOne = function updateOne(doc, options, callback) {
853
853
  const query = this.constructor.updateOne({ _id: this._id }, doc, options);
854
- query.pre(cb => {
855
- this.constructor._middleware.execPre('updateOne', this, [this], cb);
854
+ const self = this;
855
+ query.pre(function queryPreUpdateOne(cb) {
856
+ self.constructor._middleware.execPre('updateOne', self, [self], cb);
856
857
  });
857
- query.post(cb => {
858
- this.constructor._middleware.execPost('updateOne', this, [this], {}, cb);
858
+ query.post(function queryPostUpdateOne(cb) {
859
+ self.constructor._middleware.execPost('updateOne', self, [self], {}, cb);
859
860
  });
860
861
 
861
862
  if (this.$session() != null) {
@@ -1735,7 +1736,7 @@ Document.prototype.$inc = function $inc(path, val) {
1735
1736
  this.invalidate(path, new MongooseError.CastError('number', val, path, err));
1736
1737
  }
1737
1738
 
1738
- const currentValue = this.$__getValue(path);
1739
+ const currentValue = this.$__getValue(path) || 0;
1739
1740
 
1740
1741
  this.$__setValue(path, currentValue + val);
1741
1742
 
@@ -12,6 +12,8 @@ const utils = require('../../utils');
12
12
  */
13
13
 
14
14
  module.exports = function applyMethods(model, schema) {
15
+ const Model = require('../../model');
16
+
15
17
  function apply(method, schema) {
16
18
  Object.defineProperty(model.prototype, method, {
17
19
  get: function() {
@@ -34,7 +36,8 @@ module.exports = function applyMethods(model, schema) {
34
36
  // Avoid making custom methods if user sets a method to itself, e.g.
35
37
  // `schema.method(save, Document.prototype.save)`. Can happen when
36
38
  // calling `loadClass()` with a class that `extends Document`. See gh-12254
37
- if (typeof fn === 'function' && model.prototype[method] === fn) {
39
+ if (typeof fn === 'function' &&
40
+ Model.prototype[method] === fn) {
38
41
  delete schema.methods[method];
39
42
  continue;
40
43
  }
@@ -77,8 +77,8 @@ module.exports = function cast$expr(val, schema, strictQuery) {
77
77
  };
78
78
 
79
79
  function _castExpression(val, schema, strictQuery) {
80
- if (isPath(val)) {
81
- // Assume path
80
+ // Preserve the value if it represents a path or if it's null
81
+ if (isPath(val) || val === null) {
82
82
  return val;
83
83
  }
84
84
 
@@ -39,7 +39,7 @@ module.exports = function setupTimestamps(schema, timestamps) {
39
39
 
40
40
  schema.add(schemaAdditions);
41
41
 
42
- schema.pre('save', function(next) {
42
+ schema.pre('save', function timestampsPreSave(next) {
43
43
  const timestampOption = get(this, '$__.saveOptions.timestamps');
44
44
  if (timestampOption === false) {
45
45
  return next();
package/lib/model.js CHANGED
@@ -2172,7 +2172,7 @@ Model.deleteMany = function deleteMany(conditions, options, callback) {
2172
2172
  * See our [query casting tutorial](/docs/tutorials/query_casting.html) for
2173
2173
  * more information on how Mongoose casts `filter`.
2174
2174
  *
2175
- * #### Examples:
2175
+ * #### Example:
2176
2176
  *
2177
2177
  * // find all documents
2178
2178
  * await MyModel.find({});
@@ -2537,7 +2537,7 @@ Model.$where = function $where() {
2537
2537
  *
2538
2538
  * Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes if `callback` is passed else a Query object is returned.
2539
2539
  *
2540
- * #### Examples:
2540
+ * #### Example:
2541
2541
  *
2542
2542
  * A.findOneAndUpdate(conditions, update, options, callback) // executes
2543
2543
  * A.findOneAndUpdate(conditions, update, options) // returns Query
@@ -2558,6 +2558,7 @@ Model.$where = function $where() {
2558
2558
  * Model.findOneAndUpdate(query, { $set: { name: 'jason bourne' }}, options, callback)
2559
2559
  *
2560
2560
  * This helps prevent accidentally overwriting your document with `{ name: 'jason bourne' }`.
2561
+ * To prevent this behaviour, see the `overwrite` option
2561
2562
  *
2562
2563
  * #### Note:
2563
2564
  *
@@ -2670,7 +2671,7 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
2670
2671
  *
2671
2672
  * - `findOneAndUpdate()`
2672
2673
  *
2673
- * #### Examples:
2674
+ * #### Example:
2674
2675
  *
2675
2676
  * A.findByIdAndUpdate(id, update, options, callback) // executes
2676
2677
  * A.findByIdAndUpdate(id, update, options) // returns Query
@@ -2690,6 +2691,7 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
2690
2691
  * Model.findByIdAndUpdate(id, { $set: { name: 'jason bourne' }}, options, callback)
2691
2692
  *
2692
2693
  * This helps prevent accidentally overwriting your document with `{ name: 'jason bourne' }`.
2694
+ * To prevent this behaviour, see the `overwrite` option
2693
2695
  *
2694
2696
  * #### Note:
2695
2697
  *
@@ -2767,7 +2769,7 @@ Model.findByIdAndUpdate = function(id, update, options, callback) {
2767
2769
  * this distinction is purely pedantic. You should use `findOneAndDelete()`
2768
2770
  * unless you have a good reason not to.
2769
2771
  *
2770
- * #### Examples:
2772
+ * #### Example:
2771
2773
  *
2772
2774
  * A.findOneAndDelete(conditions, options, callback) // executes
2773
2775
  * A.findOneAndDelete(conditions, options) // return Query
@@ -2873,7 +2875,7 @@ Model.findByIdAndDelete = function(id, options, callback) {
2873
2875
  *
2874
2876
  * - `findOneAndReplace()`
2875
2877
  *
2876
- * #### Examples:
2878
+ * #### Example:
2877
2879
  *
2878
2880
  * A.findOneAndReplace(filter, replacement, options, callback) // executes
2879
2881
  * A.findOneAndReplace(filter, replacement, options) // return Query
@@ -2947,7 +2949,7 @@ Model.findOneAndReplace = function(filter, replacement, options, callback) {
2947
2949
  *
2948
2950
  * - `findOneAndRemove()`
2949
2951
  *
2950
- * #### Examples:
2952
+ * #### Example:
2951
2953
  *
2952
2954
  * A.findOneAndRemove(conditions, options, callback) // executes
2953
2955
  * A.findOneAndRemove(conditions, options) // return Query
@@ -3020,7 +3022,7 @@ Model.findOneAndRemove = function(conditions, options, callback) {
3020
3022
  *
3021
3023
  * - `findOneAndRemove()`
3022
3024
  *
3023
- * #### Examples:
3025
+ * #### Example:
3024
3026
  *
3025
3027
  * A.findByIdAndRemove(id, options, callback) // executes
3026
3028
  * A.findByIdAndRemove(id, options) // return Query
@@ -3967,7 +3969,7 @@ Model.hydrate = function(obj, projection, options) {
3967
3969
  *
3968
3970
  * This method is deprecated. See [Deprecation Warnings](../deprecations.html#update) for details.
3969
3971
  *
3970
- * #### Examples:
3972
+ * #### Example:
3971
3973
  *
3972
3974
  * MyModel.update({ age: { $gt: 18 } }, { oldEnough: true }, fn);
3973
3975
  *
@@ -4524,7 +4526,7 @@ Model.validate = function validate(obj, pathsToValidate, context, callback) {
4524
4526
  * - justOne: optional boolean, if true Mongoose will always set `path` to an array. Inferred from schema by default.
4525
4527
  * - strictPopulate: optional boolean, set to `false` to allow populating paths that aren't in the schema.
4526
4528
  *
4527
- * #### Examples:
4529
+ * #### Example:
4528
4530
  *
4529
4531
  * const Dog = mongoose.model('Dog', new Schema({ name: String, breed: String }));
4530
4532
  * const Person = mongoose.model('Person', new Schema({
@@ -5069,8 +5071,9 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
5069
5071
  model.Query = function() {
5070
5072
  Query.apply(this, arguments);
5071
5073
  };
5072
- model.Query.prototype = Object.create(Query.prototype);
5074
+ Object.setPrototypeOf(model.Query.prototype, Query.prototype);
5073
5075
  model.Query.base = Query.base;
5076
+ model.Query.prototype.constructor = Query;
5074
5077
  applyQueryMiddleware(model.Query, model);
5075
5078
  applyQueryMethods(model, schema.query);
5076
5079
 
@@ -4,11 +4,11 @@
4
4
  * ignore
5
5
  */
6
6
 
7
- module.exports = function(schema) {
7
+ module.exports = function clearValidating(schema) {
8
8
  // `this.$__.validating` tracks whether there are multiple validations running
9
9
  // in parallel. We need to clear `this.$__.validating` before post hooks for gh-8597
10
10
  const unshift = true;
11
- schema.s.hooks.post('validate', false, function() {
11
+ schema.s.hooks.post('validate', false, function clearValidatingPostValidate() {
12
12
  if (this.$isSubdocument) {
13
13
  return;
14
14
  }
@@ -16,7 +16,7 @@ module.exports = function(schema) {
16
16
  this.$__.validating = null;
17
17
  }, unshift);
18
18
 
19
- schema.s.hooks.post('validate', false, function(error, res, next) {
19
+ schema.s.hooks.post('validate', false, function clearValidatingPostValidateError(error, res, next) {
20
20
  if (this.$isSubdocument) {
21
21
  next();
22
22
  return;
@@ -6,9 +6,9 @@ const each = require('../helpers/each');
6
6
  * ignore
7
7
  */
8
8
 
9
- module.exports = function(schema) {
9
+ module.exports = function removeSubdocs(schema) {
10
10
  const unshift = true;
11
- schema.s.hooks.pre('remove', false, function(next) {
11
+ schema.s.hooks.pre('remove', false, function removeSubDocsPreRemove(next) {
12
12
  if (this.$isSubdocument) {
13
13
  next();
14
14
  return;
@@ -6,9 +6,9 @@ const each = require('../helpers/each');
6
6
  * ignore
7
7
  */
8
8
 
9
- module.exports = function(schema) {
9
+ module.exports = function saveSubdocs(schema) {
10
10
  const unshift = true;
11
- schema.s.hooks.pre('save', false, function(next) {
11
+ schema.s.hooks.pre('save', false, function saveSubdocsPreSave(next) {
12
12
  if (this.$isSubdocument) {
13
13
  next();
14
14
  return;
@@ -36,7 +36,7 @@ module.exports = function(schema) {
36
36
  });
37
37
  }, null, unshift);
38
38
 
39
- schema.s.hooks.post('save', function(doc, next) {
39
+ schema.s.hooks.post('save', function saveSubdocsPostSave(doc, next) {
40
40
  if (this.$isSubdocument) {
41
41
  next();
42
42
  return;
@@ -8,19 +8,19 @@ const utils = require('../utils');
8
8
  */
9
9
 
10
10
  module.exports = function shardingPlugin(schema) {
11
- schema.post('init', function() {
11
+ schema.post('init', function shardingPluginPostInit() {
12
12
  storeShard.call(this);
13
13
  return this;
14
14
  });
15
- schema.pre('save', function(next) {
15
+ schema.pre('save', function shardingPluginPreSave(next) {
16
16
  applyWhere.call(this);
17
17
  next();
18
18
  });
19
- schema.pre('remove', function(next) {
19
+ schema.pre('remove', function shardingPluginPreRemove(next) {
20
20
  applyWhere.call(this);
21
21
  next();
22
22
  });
23
- schema.post('save', function() {
23
+ schema.post('save', function shardingPluginPostSave() {
24
24
  storeShard.call(this);
25
25
  });
26
26
  };
@@ -5,7 +5,7 @@ const sessionNewDocuments = require('../helpers/symbols').sessionNewDocuments;
5
5
  const utils = require('../utils');
6
6
 
7
7
  module.exports = function trackTransaction(schema) {
8
- schema.pre('save', function() {
8
+ schema.pre('save', function trackTransactionPreSave() {
9
9
  const session = this.$session();
10
10
  if (session == null) {
11
11
  return;
@@ -4,7 +4,7 @@
4
4
  * ignore
5
5
  */
6
6
 
7
- module.exports = function(schema) {
7
+ module.exports = function validateBeforeSave(schema) {
8
8
  const unshift = true;
9
9
  schema.pre('save', false, function validateBeforeSave(next, options) {
10
10
  const _this = this;
package/lib/query.js CHANGED
@@ -280,7 +280,7 @@ Query.prototype.clone = function clone() {
280
280
  const model = this.model;
281
281
  const collection = this.mongooseCollection;
282
282
 
283
- const q = new this.constructor({}, {}, model, collection);
283
+ const q = new this.model.Query({}, {}, model, collection);
284
284
 
285
285
  // Need to handle `sort()` separately because entries-style `sort()` syntax
286
286
  // `sort([['prop1', 1]])` confuses mquery into losing the outer nested array.
@@ -3340,7 +3340,7 @@ function prepareDiscriminatorCriteria(query) {
3340
3340
  * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
3341
3341
  * }
3342
3342
  *
3343
- * #### Examples:
3343
+ * #### Example:
3344
3344
  *
3345
3345
  * query.findOneAndUpdate(conditions, update, options, callback) // executes
3346
3346
  * query.findOneAndUpdate(conditions, update, options) // returns Query
@@ -3486,7 +3486,7 @@ Query.prototype._findOneAndUpdate = wrapThunk(function(callback) {
3486
3486
  * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
3487
3487
  * }
3488
3488
  *
3489
- * #### Examples:
3489
+ * #### Example:
3490
3490
  *
3491
3491
  * A.where().findOneAndRemove(conditions, options, callback) // executes
3492
3492
  * A.where().findOneAndRemove(conditions, options) // return Query
@@ -3574,7 +3574,7 @@ Query.prototype.findOneAndRemove = function(conditions, options, callback) {
3574
3574
  * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
3575
3575
  * }
3576
3576
  *
3577
- * #### Examples:
3577
+ * #### Example:
3578
3578
  *
3579
3579
  * A.where().findOneAndDelete(conditions, options, callback) // executes
3580
3580
  * A.where().findOneAndDelete(conditions, options) // return Query
@@ -3696,7 +3696,7 @@ Query.prototype._findOneAndDelete = wrapThunk(function(callback) {
3696
3696
  * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
3697
3697
  * }
3698
3698
  *
3699
- * #### Examples:
3699
+ * #### Example:
3700
3700
  *
3701
3701
  * A.where().findOneAndReplace(filter, replacement, options, callback); // executes
3702
3702
  * A.where().findOneAndReplace(filter, replacement, options); // return Query
@@ -4863,7 +4863,7 @@ function _orFailError(err, query) {
4863
4863
  /**
4864
4864
  * Executes the query
4865
4865
  *
4866
- * #### Examples:
4866
+ * #### Example:
4867
4867
  *
4868
4868
  * const promise = query.exec();
4869
4869
  * const promise = query.exec('update');
@@ -232,6 +232,9 @@ exports.applyPaths = function applyPaths(fields, schema) {
232
232
  schema.eachPath(function(path, type) {
233
233
  if (prefix) path = prefix + '.' + path;
234
234
  if (type.$isSchemaMap || path.endsWith('.$*')) {
235
+ if (type.options && type.options.select === false) {
236
+ excluded.push(path);
237
+ }
235
238
  return;
236
239
  }
237
240
  let addedPath = analyzePath(path, type);
@@ -9,6 +9,7 @@ const EventEmitter = require('events').EventEmitter;
9
9
  const ObjectExpectedError = require('../error/objectExpected');
10
10
  const SchemaSubdocumentOptions = require('../options/SchemaSubdocumentOptions');
11
11
  const SchemaType = require('../schematype');
12
+ const applyDefaults = require('../helpers/document/applyDefaults');
12
13
  const $exists = require('./operators/exists');
13
14
  const castToNumber = require('./operators/helpers').castToNumber;
14
15
  const discriminator = require('../helpers/model/discriminator');
@@ -170,8 +171,9 @@ SubdocumentPath.prototype.cast = function(val, doc, init, priorVal, options) {
170
171
  }, null);
171
172
  options = Object.assign({}, options, { priorDoc: priorVal });
172
173
  if (init) {
173
- subdoc = new Constructor(void 0, selected, doc);
174
+ subdoc = new Constructor(void 0, selected, doc, false, { defaults: false });
174
175
  subdoc.$init(val);
176
+ applyDefaults(subdoc, selected);
175
177
  } else {
176
178
  if (Object.keys(val).length === 0) {
177
179
  return new Constructor({}, selected, doc, undefined, options);
package/lib/schema.js CHANGED
@@ -2013,7 +2013,7 @@ Schema.prototype.virtual = function(name, options) {
2013
2013
  throw new Error('Reference virtuals require `foreignField` option');
2014
2014
  }
2015
2015
 
2016
- this.pre('init', function(obj) {
2016
+ this.pre('init', function virtualPreInit(obj) {
2017
2017
  if (mpath.has(name, obj)) {
2018
2018
  const _v = mpath.get(name, obj);
2019
2019
  if (!this.$$populatedVirtuals) {
package/lib/schematype.js CHANGED
@@ -793,7 +793,7 @@ SchemaType.prototype.get = function(fn) {
793
793
  *
794
794
  * The error message argument is optional. If not passed, the [default generic error message template](#error_messages_MongooseError-messages) will be used.
795
795
  *
796
- * #### Examples:
796
+ * #### Example:
797
797
  *
798
798
  * // make sure every value is equal to "something"
799
799
  * function validator (val) {
@@ -5,6 +5,7 @@ const ArraySubdocument = require('../../ArraySubdocument');
5
5
  const MongooseError = require('../../../error/mongooseError');
6
6
  const cleanModifiedSubpaths = require('../../../helpers/document/cleanModifiedSubpaths');
7
7
  const internalToObjectOptions = require('../../../options').internalToObjectOptions;
8
+ const mpath = require('mpath');
8
9
  const utils = require('../../../utils');
9
10
  const isBsonType = require('../../../helpers/isBsonType');
10
11
 
@@ -341,8 +342,23 @@ const methods = {
341
342
  const pullOp = atomics['$pull'] || (atomics['$pull'] = {});
342
343
  if (val[0] instanceof ArraySubdocument) {
343
344
  selector = pullOp['$or'] || (pullOp['$or'] = []);
344
- Array.prototype.push.apply(selector, val.map(function(v) {
345
- return v.toObject({ transform: false, virtuals: false });
345
+ Array.prototype.push.apply(selector, val.map(v => {
346
+ return v.toObject({
347
+ transform: (doc, ret) => {
348
+ if (v == null || v.$__ == null) {
349
+ return ret;
350
+ }
351
+
352
+ Object.keys(v.$__.activePaths.getStatePaths('default')).forEach(path => {
353
+ mpath.unset(path, ret);
354
+
355
+ _minimizePath(ret, path);
356
+ });
357
+
358
+ return ret;
359
+ },
360
+ virtuals: false
361
+ });
346
362
  }));
347
363
  } else {
348
364
  selector = pullOp['_id'] || (pullOp['_id'] = { $in: [] });
@@ -541,7 +557,7 @@ const methods = {
541
557
  * the provided value to an embedded document and comparing using
542
558
  * [the `Document.equals()` function.](/docs/api.html#document_Document-equals)
543
559
  *
544
- * #### Examples:
560
+ * #### Example:
545
561
  *
546
562
  * doc.array.pull(ObjectId)
547
563
  * doc.array.pull({ _id: 'someId' })
@@ -590,7 +606,11 @@ const methods = {
590
606
 
591
607
  if (values[0] instanceof ArraySubdocument) {
592
608
  this._registerAtomic('$pullDocs', values.map(function(v) {
593
- return v.$__getValue('_id') || v;
609
+ const _id = v.$__getValue('_id');
610
+ if (_id === undefined || v.$isDefault('_id')) {
611
+ return v;
612
+ }
613
+ return _id;
594
614
  }));
595
615
  } else {
596
616
  this._registerAtomic('$pullAll', values);
@@ -920,6 +940,40 @@ function _isAllSubdocs(docs, ref) {
920
940
  return true;
921
941
  }
922
942
 
943
+ /*!
944
+ * Minimize _just_ empty objects along the path chain specified
945
+ * by `parts`, ignoring all other paths. Useful in cases where
946
+ * you want to minimize after unsetting a path.
947
+ *
948
+ * #### Example:
949
+ *
950
+ * const obj = { foo: { bar: { baz: {} } }, a: {} };
951
+ * _minimizePath(obj, 'foo.bar.baz');
952
+ * obj; // { a: {} }
953
+ */
954
+
955
+ function _minimizePath(obj, parts, i) {
956
+ if (typeof parts === 'string') {
957
+ if (parts.indexOf('.') === -1) {
958
+ return;
959
+ }
960
+
961
+ parts = mpath.stringToParts(parts);
962
+ }
963
+ i = i || 0;
964
+ if (i >= parts.length) {
965
+ return;
966
+ }
967
+ if (obj == null || typeof obj !== 'object') {
968
+ return;
969
+ }
970
+
971
+ _minimizePath(obj[parts[0]], parts, i + 1);
972
+ if (obj[parts[0]] != null && typeof obj[parts[0]] === 'object' && Object.keys(obj[parts[0]]).length === 0) {
973
+ delete obj[parts[0]];
974
+ }
975
+ }
976
+
923
977
  /*!
924
978
  * ignore
925
979
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "6.6.0",
4
+ "version": "6.6.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -28,9 +28,9 @@
28
28
  "sift": "16.0.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@babel/core": "7.18.13",
32
- "@typescript-eslint/eslint-plugin": "5.36.1",
33
- "@typescript-eslint/parser": "5.36.1",
31
+ "@babel/core": "7.19.0",
32
+ "@typescript-eslint/eslint-plugin": "5.36.2",
33
+ "@typescript-eslint/parser": "5.36.2",
34
34
  "acquit": "1.2.1",
35
35
  "acquit-ignore": "0.2.0",
36
36
  "acquit-require": "0.1.1",
@@ -62,8 +62,8 @@
62
62
  "stream-browserify": "3.0.0",
63
63
  "ts-benchmark": "^1.1.10",
64
64
  "tsd": "0.23.0",
65
- "typescript": "4.8.2",
66
- "uuid": "8.3.2",
65
+ "typescript": "4.8.3",
66
+ "uuid": "9.0.0",
67
67
  "webpack": "5.74.0"
68
68
  },
69
69
  "directories": {
@@ -4,4 +4,4 @@ const { execSync } = require('child_process');
4
4
  const { name, version } = require('../package.json');
5
5
 
6
6
  execSync('npm pack');
7
- execSync(`mv ${name}-${version}.tgz ${name}.tgz`);
7
+ execSync(`mv ${name}-${version}.tgz ${name}.tgz`);
@@ -2835,7 +2835,8 @@ declare module 'mongoose' {
2835
2835
  Expression.Push |
2836
2836
  Expression.StdDevPop |
2837
2837
  Expression.StdDevSamp |
2838
- Expression.Sum;
2838
+ Expression.Sum |
2839
+ Expression.TopN;
2839
2840
 
2840
2841
  export type tzExpression = UTCOffset | StringExpressionOperatorReturningBoolean | string;
2841
2842
 
package/types/index.d.ts CHANGED
@@ -58,6 +58,12 @@ declare module 'mongoose' {
58
58
  */
59
59
  export function deleteModel(name: string | RegExp): Mongoose;
60
60
 
61
+ /**
62
+ * Sanitizes query filters against query selector injection attacks by wrapping
63
+ * any nested objects that have a property whose name starts with `$` in a `$eq`.
64
+ */
65
+ export function sanitizeFilter<T>(filter: FilterQuery<T>): FilterQuery<T>;
66
+
61
67
  /** Gets mongoose options */
62
68
  export function get<K extends keyof MongooseOptions>(key: K): MongooseOptions[K];
63
69
 
@@ -118,6 +124,12 @@ declare module 'mongoose' {
118
124
 
119
125
  export type HydratedDocument<DocType, TMethodsAndOverrides = {}, TVirtuals = {}> = DocType extends Document ? Require_id<DocType> : (Document<unknown, any, DocType> & Require_id<DocType> & TVirtuals & TMethodsAndOverrides);
120
126
 
127
+ export type HydratedDocumentFromSchema<TSchema extends Schema> = HydratedDocument<
128
+ InferSchemaType<TSchema>,
129
+ ObtainSchemaGeneric<TSchema, 'TQueryHelpers'>,
130
+ ObtainSchemaGeneric<TSchema, 'TInstanceMethods'>
131
+ >;
132
+
121
133
  export interface TagSet {
122
134
  [k: string]: string;
123
135
  }
@@ -156,7 +156,7 @@ type ResolvePathType<PathValueType, Options extends SchemaTypeOptions<PathValueT
156
156
  PathValueType extends Schema ? InferSchemaType<PathValueType> :
157
157
  PathValueType extends (infer Item)[] ? IfEquals<Item, never, any[], Item extends Schema ? Types.DocumentArray<ResolvePathType<Item>> : ResolvePathType<Item>[]> :
158
158
  PathValueType extends StringSchemaDefinition ? PathEnumOrString<Options['enum']> :
159
- PathValueType extends NumberSchemaDefinition ? number :
159
+ PathValueType extends NumberSchemaDefinition ? Options['enum'] extends ReadonlyArray<any> ? Options['enum'][number] : number :
160
160
  PathValueType extends DateSchemaDefinition ? Date :
161
161
  PathValueType extends typeof Buffer | 'buffer' | 'Buffer' | typeof Schema.Types.Buffer ? Buffer :
162
162
  PathValueType extends BooleanSchemaDefinition ? boolean :