mongoose 8.6.3 → 8.6.4

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/cast.js CHANGED
@@ -65,10 +65,11 @@ module.exports = function cast(schema, obj, options, context) {
65
65
  if (!Array.isArray(val)) {
66
66
  throw new CastError('Array', val, path);
67
67
  }
68
- for (let k = 0; k < val.length; ++k) {
68
+ for (let k = val.length - 1; k >= 0; k--) {
69
69
  if (val[k] == null || typeof val[k] !== 'object') {
70
70
  throw new CastError('Object', val[k], path + '.' + k);
71
71
  }
72
+ const beforeCastKeysLength = Object.keys(val[k]).length;
72
73
  const discriminatorValue = val[k][schema.options.discriminatorKey];
73
74
  if (discriminatorValue == null) {
74
75
  val[k] = cast(schema, val[k], options, context);
@@ -76,6 +77,15 @@ module.exports = function cast(schema, obj, options, context) {
76
77
  const discriminatorSchema = getSchemaDiscriminatorByValue(context.schema, discriminatorValue);
77
78
  val[k] = cast(discriminatorSchema ? discriminatorSchema : schema, val[k], options, context);
78
79
  }
80
+
81
+ if (Object.keys(val[k]).length === 0 && beforeCastKeysLength !== 0) {
82
+ val.splice(k, 1);
83
+ }
84
+ }
85
+
86
+ // delete empty: {$or: []} -> {}
87
+ if (val.length === 0) {
88
+ delete obj[path];
79
89
  }
80
90
  } else if (path === '$where') {
81
91
  type = typeof val;
package/lib/constants.js CHANGED
@@ -34,3 +34,40 @@ const queryMiddlewareFunctions = queryOperations.concat([
34
34
  ]);
35
35
 
36
36
  exports.queryMiddlewareFunctions = queryMiddlewareFunctions;
37
+
38
+ /*!
39
+ * ignore
40
+ */
41
+
42
+ const aggregateMiddlewareFunctions = [
43
+ 'aggregate'
44
+ ];
45
+
46
+ exports.aggregateMiddlewareFunctions = aggregateMiddlewareFunctions;
47
+
48
+ /*!
49
+ * ignore
50
+ */
51
+
52
+ const modelMiddlewareFunctions = [
53
+ 'bulkWrite',
54
+ 'createCollection',
55
+ 'insertMany'
56
+ ];
57
+
58
+ exports.modelMiddlewareFunctions = modelMiddlewareFunctions;
59
+
60
+ /*!
61
+ * ignore
62
+ */
63
+
64
+ const documentMiddlewareFunctions = [
65
+ 'validate',
66
+ 'save',
67
+ 'remove',
68
+ 'updateOne',
69
+ 'deleteOne',
70
+ 'init'
71
+ ];
72
+
73
+ exports.documentMiddlewareFunctions = documentMiddlewareFunctions;
package/lib/document.js CHANGED
@@ -2689,7 +2689,7 @@ function _evaluateRequiredFunctions(doc) {
2689
2689
  * ignore
2690
2690
  */
2691
2691
 
2692
- function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
2692
+ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate) {
2693
2693
  const doValidateOptions = {};
2694
2694
 
2695
2695
  _evaluateRequiredFunctions(doc);
@@ -2709,35 +2709,40 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
2709
2709
  Object.keys(doc.$__.activePaths.getStatePaths('default')).forEach(addToPaths);
2710
2710
  function addToPaths(p) { paths.add(p); }
2711
2711
 
2712
- const subdocs = doc.$getAllSubdocs();
2713
- const modifiedPaths = doc.modifiedPaths();
2714
- for (const subdoc of subdocs) {
2715
- if (subdoc.$basePath) {
2716
- const fullPathToSubdoc = subdoc.$isSingleNested ? subdoc.$__pathRelativeToParent() : subdoc.$__fullPathWithIndexes();
2717
-
2718
- // Remove child paths for now, because we'll be validating the whole
2719
- // subdoc.
2720
- // The following is a faster take on looping through every path in `paths`
2721
- // and checking if the path starts with `fullPathToSubdoc` re: gh-13191
2722
- for (const modifiedPath of subdoc.modifiedPaths()) {
2723
- paths.delete(fullPathToSubdoc + '.' + modifiedPath);
2724
- }
2712
+ if (!isNestedValidate) {
2713
+ // If we're validating a subdocument, all this logic will run anyway on the top-level document, so skip for subdocuments
2714
+ const subdocs = doc.$getAllSubdocs();
2715
+ const modifiedPaths = doc.modifiedPaths();
2716
+ for (const subdoc of subdocs) {
2717
+ if (subdoc.$basePath) {
2718
+ const fullPathToSubdoc = subdoc.$isSingleNested ? subdoc.$__pathRelativeToParent() : subdoc.$__fullPathWithIndexes();
2719
+
2720
+ // Remove child paths for now, because we'll be validating the whole
2721
+ // subdoc.
2722
+ // The following is a faster take on looping through every path in `paths`
2723
+ // and checking if the path starts with `fullPathToSubdoc` re: gh-13191
2724
+ for (const modifiedPath of subdoc.modifiedPaths()) {
2725
+ paths.delete(fullPathToSubdoc + '.' + modifiedPath);
2726
+ }
2725
2727
 
2726
- if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2727
- !doc.isDirectModified(fullPathToSubdoc) &&
2728
- !doc.$isDefault(fullPathToSubdoc)) {
2729
- paths.add(fullPathToSubdoc);
2728
+ if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2729
+ // Avoid using isDirectModified() here because that does additional checks on whether the parent path
2730
+ // is direct modified, which can cause performance issues re: gh-14897
2731
+ !doc.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
2732
+ !doc.$isDefault(fullPathToSubdoc)) {
2733
+ paths.add(fullPathToSubdoc);
2730
2734
 
2731
- if (doc.$__.pathsToScopes == null) {
2732
- doc.$__.pathsToScopes = {};
2733
- }
2734
- doc.$__.pathsToScopes[fullPathToSubdoc] = subdoc.$isDocumentArrayElement ?
2735
- subdoc.__parentArray :
2736
- subdoc.$parent();
2735
+ if (doc.$__.pathsToScopes == null) {
2736
+ doc.$__.pathsToScopes = {};
2737
+ }
2738
+ doc.$__.pathsToScopes[fullPathToSubdoc] = subdoc.$isDocumentArrayElement ?
2739
+ subdoc.__parentArray :
2740
+ subdoc.$parent();
2737
2741
 
2738
- doValidateOptions[fullPathToSubdoc] = { skipSchemaValidators: true };
2739
- if (subdoc.$isDocumentArrayElement && subdoc.__index != null) {
2740
- doValidateOptions[fullPathToSubdoc].index = subdoc.__index;
2742
+ doValidateOptions[fullPathToSubdoc] = { skipSchemaValidators: true };
2743
+ if (subdoc.$isDocumentArrayElement && subdoc.__index != null) {
2744
+ doValidateOptions[fullPathToSubdoc].index = subdoc.__index;
2745
+ }
2741
2746
  }
2742
2747
  }
2743
2748
  }
@@ -2972,7 +2977,7 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
2972
2977
  paths = [...paths];
2973
2978
  doValidateOptionsByPath = {};
2974
2979
  } else {
2975
- const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip);
2980
+ const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip, options && options._nestedValidate);
2976
2981
  paths = shouldValidateModifiedOnly ?
2977
2982
  pathDetails[0].filter((path) => this.$isModified(path)) :
2978
2983
  pathDetails[0];
@@ -3059,7 +3064,8 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
3059
3064
  const doValidateOptions = {
3060
3065
  ...doValidateOptionsByPath[path],
3061
3066
  path: path,
3062
- validateAllPaths
3067
+ validateAllPaths,
3068
+ _nestedValidate: true
3063
3069
  };
3064
3070
 
3065
3071
  schemaType.doValidate(val, function(err) {
@@ -3478,44 +3484,9 @@ Document.prototype.$__reset = function reset() {
3478
3484
  // Skip for subdocuments
3479
3485
  const subdocs = !this.$isSubdocument ? this.$getAllSubdocs() : null;
3480
3486
  if (subdocs && subdocs.length > 0) {
3481
- const resetArrays = new Set();
3482
3487
  for (const subdoc of subdocs) {
3483
- const fullPathWithIndexes = subdoc.$__fullPathWithIndexes();
3484
3488
  subdoc.$__reset();
3485
- if (this.isModified(fullPathWithIndexes) || isParentInit(fullPathWithIndexes)) {
3486
- if (subdoc.$isDocumentArrayElement) {
3487
- resetArrays.add(subdoc.parentArray());
3488
- } else {
3489
- const parent = subdoc.$parent();
3490
- if (parent === this) {
3491
- this.$__.activePaths.clearPath(subdoc.$basePath);
3492
- } else if (parent != null && parent.$isSubdocument) {
3493
- // If map path underneath subdocument, may end up with a case where
3494
- // map path is modified but parent still needs to be reset. See gh-10295
3495
- parent.$__reset();
3496
- }
3497
- }
3498
- }
3499
- }
3500
-
3501
- for (const array of resetArrays) {
3502
- this.$__.activePaths.clearPath(array.$path());
3503
- array[arrayAtomicsBackupSymbol] = array[arrayAtomicsSymbol];
3504
- array[arrayAtomicsSymbol] = {};
3505
- }
3506
- }
3507
-
3508
- function isParentInit(path) {
3509
- path = path.indexOf('.') === -1 ? [path] : path.split('.');
3510
- let cur = '';
3511
- for (let i = 0; i < path.length; ++i) {
3512
- cur += (cur.length ? '.' : '') + path[i];
3513
- if (_this.$__.activePaths[cur] === 'init') {
3514
- return true;
3515
- }
3516
3489
  }
3517
-
3518
- return false;
3519
3490
  }
3520
3491
 
3521
3492
  // clear atomics
@@ -6,11 +6,12 @@
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
+ /**
10
+ * MissingSchema Error constructor.
11
+ */
9
12
 
10
13
  class MissingSchemaError extends MongooseError {
11
- /**
12
- * MissingSchema Error constructor.
13
- */
14
+
14
15
  constructor() {
15
16
  super('Schema hasn\'t been registered for document.\n'
16
17
  + 'Use mongoose.Document(name, schema)');
@@ -7,12 +7,14 @@
7
7
 
8
8
  const MongooseError = require('./mongooseError');
9
9
 
10
+ /**
11
+ * DivergentArrayError constructor.
12
+ * @param {Array<String>} paths
13
+ * @api private
14
+ */
15
+
10
16
  class DivergentArrayError extends MongooseError {
11
- /**
12
- * DivergentArrayError constructor.
13
- * @param {Array<String>} paths
14
- * @api private
15
- */
17
+
16
18
  constructor(paths) {
17
19
  const msg = 'For your own good, using `document.save()` to update an array '
18
20
  + 'which was selected using an $elemMatch projection OR '
@@ -7,12 +7,14 @@
7
7
 
8
8
  const MongooseError = require('./mongooseError');
9
9
 
10
+ /**
11
+ * InvalidSchemaOption Error constructor.
12
+ * @param {String} name
13
+ * @api private
14
+ */
15
+
10
16
  class InvalidSchemaOptionError extends MongooseError {
11
- /**
12
- * InvalidSchemaOption Error constructor.
13
- * @param {String} name
14
- * @api private
15
- */
17
+
16
18
  constructor(name, option) {
17
19
  const msg = `Cannot create use schema for property "${name}" because the schema has the ${option} option enabled.`;
18
20
  super(msg);
@@ -7,12 +7,14 @@
7
7
 
8
8
  const MongooseError = require('./mongooseError');
9
9
 
10
+ /**
11
+ * MissingSchema Error constructor.
12
+ * @param {String} name
13
+ * @api private
14
+ */
15
+
10
16
  class MissingSchemaError extends MongooseError {
11
- /**
12
- * MissingSchema Error constructor.
13
- * @param {String} name
14
- * @api private
15
- */
17
+
16
18
  constructor(name) {
17
19
  const msg = 'Schema hasn\'t been registered for model "' + name + '".\n'
18
20
  + 'Use mongoose.model(name, schema)';
@@ -7,11 +7,13 @@
7
7
  const MongooseError = require('./mongooseError');
8
8
  const util = require('util');
9
9
 
10
+ /**
11
+ * OverwriteModel Error constructor.
12
+ * @api private
13
+ */
14
+
10
15
  class DocumentNotFoundError extends MongooseError {
11
- /**
12
- * OverwriteModel Error constructor.
13
- * @api private
14
- */
16
+
15
17
  constructor(filter, model, numAffected, result) {
16
18
  let msg;
17
19
  const messages = MongooseError.messages;
@@ -6,15 +6,16 @@
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
+ /**
10
+ * Strict mode error constructor
11
+ *
12
+ * @param {string} type
13
+ * @param {string} value
14
+ * @api private
15
+ */
9
16
 
10
17
  class ObjectExpectedError extends MongooseError {
11
- /**
12
- * Strict mode error constructor
13
- *
14
- * @param {string} type
15
- * @param {string} value
16
- * @api private
17
- */
18
+
18
19
  constructor(path, val) {
19
20
  const typeDescription = Array.isArray(val) ? 'array' : 'primitive value';
20
21
  super('Tried to set nested object field `' + path +
@@ -6,16 +6,18 @@
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
+ /**
10
+ * Constructor for errors that happen when a parameter that's expected to be
11
+ * an object isn't an object
12
+ *
13
+ * @param {Any} value
14
+ * @param {String} paramName
15
+ * @param {String} fnName
16
+ * @api private
17
+ */
18
+
9
19
  class ObjectParameterError extends MongooseError {
10
- /**
11
- * Constructor for errors that happen when a parameter that's expected to be
12
- * an object isn't an object
13
- *
14
- * @param {Any} value
15
- * @param {String} paramName
16
- * @param {String} fnName
17
- * @api private
18
- */
20
+
19
21
  constructor(value, paramName, fnName) {
20
22
  super('Parameter "' + paramName + '" to ' + fnName +
21
23
  '() must be an object, got "' + value.toString() + '" (type ' + typeof value + ')');
@@ -7,13 +7,14 @@
7
7
 
8
8
  const MongooseError = require('./mongooseError');
9
9
 
10
+ /**
11
+ * OverwriteModel Error constructor.
12
+ * @param {String} name
13
+ * @api private
14
+ */
10
15
 
11
16
  class OverwriteModelError extends MongooseError {
12
- /**
13
- * OverwriteModel Error constructor.
14
- * @param {String} name
15
- * @api private
16
- */
17
+
17
18
  constructor(name) {
18
19
  super('Cannot overwrite `' + name + '` model once compiled.');
19
20
  }
@@ -6,13 +6,16 @@
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
+
10
+ /**
11
+ * ParallelSave Error constructor.
12
+ *
13
+ * @param {Document} doc
14
+ * @api private
15
+ */
16
+
9
17
  class ParallelSaveError extends MongooseError {
10
- /**
11
- * ParallelSave Error constructor.
12
- *
13
- * @param {Document} doc
14
- * @api private
15
- */
18
+
16
19
  constructor(doc) {
17
20
  const msg = 'Can\'t save() the same doc multiple times in parallel. Document: ';
18
21
  super(msg + doc._doc._id);
@@ -7,13 +7,15 @@
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
9
 
10
+ /**
11
+ * ParallelValidate Error constructor.
12
+ *
13
+ * @param {Document} doc
14
+ * @api private
15
+ */
16
+
10
17
  class ParallelValidateError extends MongooseError {
11
- /**
12
- * ParallelValidate Error constructor.
13
- *
14
- * @param {Document} doc
15
- * @api private
16
- */
18
+
17
19
  constructor(doc) {
18
20
  const msg = 'Can\'t validate() the same doc multiple times in parallel. Document: ';
19
21
  super(msg + doc._doc._id);
@@ -8,13 +8,15 @@ const MongooseError = require('./mongooseError');
8
8
  const util = require('util');
9
9
  const combinePathErrors = require('../helpers/error/combinePathErrors');
10
10
 
11
+ /**
12
+ * Mongoose.set Error
13
+ *
14
+ * @api private
15
+ * @inherits MongooseError
16
+ */
17
+
11
18
  class SetOptionError extends MongooseError {
12
- /**
13
- * Mongoose.set Error
14
- *
15
- * @api private
16
- * @inherits MongooseError
17
- */
19
+
18
20
  constructor() {
19
21
  super('');
20
22
 
@@ -6,17 +6,19 @@
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
+ /**
10
+ * Strict mode error constructor
11
+ *
12
+ * @param {String} path
13
+ * @param {String} [msg]
14
+ * @param {Boolean} [immutable]
15
+ * @inherits MongooseError
16
+ * @api private
17
+ */
18
+
9
19
 
10
20
  class StrictModeError extends MongooseError {
11
- /**
12
- * Strict mode error constructor
13
- *
14
- * @param {String} path
15
- * @param {String} [msg]
16
- * @param {Boolean} [immutable]
17
- * @inherits MongooseError
18
- * @api private
19
- */
21
+
20
22
  constructor(path, msg, immutable) {
21
23
  msg = msg || 'Field `' + path + '` is not in schema and strict ' +
22
24
  'mode is set to throw.';
@@ -6,15 +6,17 @@
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
+ /**
10
+ * Strict mode error constructor
11
+ *
12
+ * @param {String} path
13
+ * @param {String} [msg]
14
+ * @inherits MongooseError
15
+ * @api private
16
+ */
17
+
9
18
  class StrictPopulateError extends MongooseError {
10
- /**
11
- * Strict mode error constructor
12
- *
13
- * @param {String} path
14
- * @param {String} [msg]
15
- * @inherits MongooseError
16
- * @api private
17
- */
19
+
18
20
  constructor(path, msg) {
19
21
  msg = msg || 'Cannot populate path `' + path + '` because it is not in your schema. ' + 'Set the `strictPopulate` option to false to override.';
20
22
  super(msg);
@@ -9,14 +9,16 @@ const getConstructorName = require('../helpers/getConstructorName');
9
9
  const util = require('util');
10
10
  const combinePathErrors = require('../helpers/error/combinePathErrors');
11
11
 
12
+ /**
13
+ * Document Validation Error
14
+ *
15
+ * @api private
16
+ * @param {Document} [instance]
17
+ * @inherits MongooseError
18
+ */
19
+
12
20
  class ValidationError extends MongooseError {
13
- /**
14
- * Document Validation Error
15
- *
16
- * @api private
17
- * @param {Document} [instance]
18
- * @inherits MongooseError
19
- */
21
+
20
22
  constructor(instance) {
21
23
  let _message;
22
24
  if (getConstructorName(instance) === 'model') {
@@ -6,15 +6,16 @@
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
+ /**
10
+ * Schema validator error
11
+ *
12
+ * @param {Object} properties
13
+ * @param {Document} doc
14
+ * @api private
15
+ */
9
16
 
10
17
  class ValidatorError extends MongooseError {
11
- /**
12
- * Schema validator error
13
- *
14
- * @param {Object} properties
15
- * @param {Document} doc
16
- * @api private
17
- */
18
+
18
19
  constructor(properties, doc) {
19
20
  let msg = properties.message;
20
21
  if (!msg) {
@@ -6,15 +6,17 @@
6
6
 
7
7
  const MongooseError = require('./mongooseError');
8
8
 
9
+ /**
10
+ * Version Error constructor.
11
+ *
12
+ * @param {Document} doc
13
+ * @param {Number} currentVersion
14
+ * @param {Array<String>} modifiedPaths
15
+ * @api private
16
+ */
17
+
9
18
  class VersionError extends MongooseError {
10
- /**
11
- * Version Error constructor.
12
- *
13
- * @param {Document} doc
14
- * @param {Number} currentVersion
15
- * @param {Array<String>} modifiedPaths
16
- * @api private
17
- */
19
+
18
20
  constructor(doc, currentVersion, modifiedPaths) {
19
21
  const modifiedPathsStr = modifiedPaths.join(', ');
20
22
  super('No matching document found for id "' + doc._doc._id +
@@ -1,7 +1,16 @@
1
1
  'use strict';
2
2
 
3
- const middlewareFunctions = require('../../constants').queryMiddlewareFunctions;
4
3
  const promiseOrCallback = require('../promiseOrCallback');
4
+ const { queryMiddlewareFunctions, aggregateMiddlewareFunctions, modelMiddlewareFunctions, documentMiddlewareFunctions } = require('../../constants');
5
+
6
+ const middlewareFunctions = Array.from(
7
+ new Set([
8
+ ...queryMiddlewareFunctions,
9
+ ...aggregateMiddlewareFunctions,
10
+ ...modelMiddlewareFunctions,
11
+ ...documentMiddlewareFunctions
12
+ ])
13
+ );
5
14
 
6
15
  module.exports = function applyStaticHooks(model, hooks, statics) {
7
16
  const kareemOptions = {
@@ -9,8 +18,11 @@ module.exports = function applyStaticHooks(model, hooks, statics) {
9
18
  numCallbackParams: 1
10
19
  };
11
20
 
21
+ model.$__insertMany = hooks.createWrapper('insertMany',
22
+ model.$__insertMany, model, kareemOptions);
23
+
12
24
  hooks = hooks.filter(hook => {
13
- // If the custom static overwrites an existing query middleware, don't apply
25
+ // If the custom static overwrites an existing middleware, don't apply
14
26
  // middleware to it by default. This avoids a potential backwards breaking
15
27
  // change with plugins like `mongoose-delete` that use statics to overwrite
16
28
  // built-in Mongoose functions.
@@ -20,9 +32,6 @@ module.exports = function applyStaticHooks(model, hooks, statics) {
20
32
  return hook.model !== false;
21
33
  });
22
34
 
23
- model.$__insertMany = hooks.createWrapper('insertMany',
24
- model.$__insertMany, model, kareemOptions);
25
-
26
35
  for (const key of Object.keys(statics)) {
27
36
  if (hooks.hasHooks(key)) {
28
37
  const original = model[key];
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const isDefiningProjection = require('./isDefiningProjection');
4
+ const isPOJO = require('../isPOJO');
4
5
 
5
6
  /*!
6
7
  * ignore
@@ -22,10 +23,12 @@ module.exports = function isExclusive(projection) {
22
23
  // Explicitly avoid `$meta` and `$slice`
23
24
  const key = keys[ki];
24
25
  if (key !== '_id' && isDefiningProjection(projection[key])) {
25
- exclude = (projection[key] != null && typeof projection[key] === 'object') ?
26
- isExclusive(projection[key]) :
26
+ exclude = isPOJO(projection[key]) ?
27
+ (isExclusive(projection[key]) ?? exclude) :
27
28
  !projection[key];
28
- break;
29
+ if (exclude != null) {
30
+ break;
31
+ }
29
32
  }
30
33
  }
31
34
  }
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const isDefiningProjection = require('./isDefiningProjection');
4
+ const isPOJO = require('../isPOJO');
4
5
 
5
6
  /*!
6
7
  * ignore
@@ -26,7 +27,7 @@ module.exports = function isInclusive(projection) {
26
27
  // If field is truthy (1, true, etc.) and not an object, then this
27
28
  // projection must be inclusive. If object, assume its $meta, $slice, etc.
28
29
  if (isDefiningProjection(projection[prop]) && !!projection[prop]) {
29
- if (projection[prop] != null && typeof projection[prop] === 'object') {
30
+ if (isPOJO(projection[prop])) {
30
31
  return isInclusive(projection[prop]);
31
32
  } else {
32
33
  return !!projection[prop];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "8.6.3",
4
+ "version": "8.6.4",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",