mongoose 9.11.1 → 9.11.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/lib/aggregate.js CHANGED
@@ -1174,7 +1174,7 @@ Aggregate.prototype.then = function(resolve, reject) {
1174
1174
  /**
1175
1175
  * Executes the aggregation returning a `Promise` which will be
1176
1176
  * resolved with either the doc(s) or rejected with the error.
1177
- * Like [`.then()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.then), but only takes a rejection handler.
1177
+ * Like [`.then()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.then()), but only takes a rejection handler.
1178
1178
  * Compatible with `await`.
1179
1179
  *
1180
1180
  * @param {Function} [reject]
package/lib/document.js CHANGED
@@ -76,7 +76,7 @@ const VERSION_ALL = VERSION_WHERE | VERSION_INC;
76
76
 
77
77
  /**
78
78
  * The core Mongoose document constructor. You should not call this directly,
79
- * the Mongoose [Model constructor](./api/model.html#Model) calls this for you.
79
+ * the Mongoose [Model constructor](./api/model.html#Model()) calls this for you.
80
80
  *
81
81
  * @param {object} obj the values to set
82
82
  * @param {object} [fields] optional object containing the fields which were selected in the query returning this document and any populated paths data
@@ -879,9 +879,9 @@ function init(self, obj, doc, opts, prefix) {
879
879
  *
880
880
  * #### Valid options:
881
881
  *
882
- * - same as in [Model.updateOne](https://mongoosejs.com/docs/api/model.html#Model.updateOne)
882
+ * - same as in [Model.updateOne](https://mongoosejs.com/docs/api/model.html#Model.updateOne())
883
883
  *
884
- * @see Model.updateOne https://mongoosejs.com/docs/api/model.html#Model.updateOne
884
+ * @see Model.updateOne https://mongoosejs.com/docs/api/model.html#Model.updateOne()
885
885
  * @param {object} update
886
886
  * @param {object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
887
887
  * @param {object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.lean()) and the [Mongoose lean tutorial](https://mongoosejs.com/docs/tutorials/lean.html).
@@ -3791,7 +3791,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
3791
3791
  }
3792
3792
 
3793
3793
  /**
3794
- * Saves this document by inserting a new document into the database if [document.isNew](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew()) is `true`,
3794
+ * Saves this document by inserting a new document into the database if [document.isNew](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew) is `true`,
3795
3795
  * or sends an [updateOne](https://mongoosejs.com/docs/api/document.html#Document.prototype.updateOne()) operation **only** with the modifications to the database, it does not replace the whole document in the latter case.
3796
3796
  *
3797
3797
  * #### Example:
@@ -3824,7 +3824,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
3824
3824
  * @method save
3825
3825
  * @memberOf Document
3826
3826
  * @instance
3827
- * @throws {DocumentNotFoundError} if this [save updates an existing document](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew()) but the document doesn't exist in the database. For example, you will get this error if the document is [deleted between when you retrieved the document and when you saved it](documents.html#updating).
3827
+ * @throws {DocumentNotFoundError} if this [save updates an existing document](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew) but the document doesn't exist in the database. For example, you will get this error if the document is [deleted between when you retrieved the document and when you saved it](documents.html#updating).
3828
3828
  * @return {Promise}
3829
3829
  * @api public
3830
3830
  * @see middleware https://mongoosejs.com/docs/middleware.html
@@ -4071,7 +4071,7 @@ Document.prototype.$__setSchema = function(schema) {
4071
4071
  this.schema = schema;
4072
4072
  }
4073
4073
  this.$__schema = schema;
4074
- this.$__middleware = schema._getDocumentMiddleware();
4074
+ this.$__middleware = schema._getDocumentMiddleware(this.$isSubdocument);
4075
4075
  this[documentSchemaSymbol] = schema;
4076
4076
  };
4077
4077
 
@@ -26,14 +26,14 @@ const MongooseError = require('./mongooseError');
26
26
  * - `MongooseError`: general Mongoose error
27
27
  * - `CastError`: Mongoose could not convert a value to the type defined in the schema path. May be in a `ValidationError` class' `errors` property.
28
28
  * - `DivergentArrayError`: You attempted to `save()` an array that was modified after you loaded it with a `$elemMatch` or similar projection
29
- * - `MissingSchemaError`: You tried to access a model with [`mongoose.model()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.model()) that was not defined
29
+ * - `MissingSchemaError`: You tried to access a model with [`mongoose.model()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.model()) that was not defined
30
30
  * - `DocumentNotFoundError`: The document you tried to [`save()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.save()) was not found
31
31
  * - `ValidatorError`: error from an individual schema path's validator
32
32
  * - `ValidationError`: error returned from [`validate()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.validate()) or [`validateSync()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.validateSync()). Contains zero or more `ValidatorError` instances in `.errors` property.
33
33
  * - `MissingSchemaError`: You called `mongoose.Document()` without a schema
34
34
  * - `ObjectExpectedError`: Thrown when you set a nested path to a non-object value with [strict mode set](https://mongoosejs.com/docs/guide.html#strict).
35
35
  * - `ObjectParameterError`: Thrown when you pass a non-object value to a function which expects an object as a parameter
36
- * - `OverwriteModelError`: Thrown when you call [`mongoose.model()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.model()) to re-define a model that was already defined.
36
+ * - `OverwriteModelError`: Thrown when you call [`mongoose.model()`](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.model()) to re-define a model that was already defined.
37
37
  * - `ParallelSaveError`: Thrown when you call [`save()`](https://mongoosejs.com/docs/api/model.html#Model.prototype.save()) on a document when the same document instance is already saving.
38
38
  * - `StrictModeError`: Thrown when you set a path that isn't the schema and [strict mode](https://mongoosejs.com/docs/guide.html#strict) is set to `throw`.
39
39
  * - `VersionError`: Thrown when the [document is out of sync](https://mongoosejs.com/docs/guide.html#versionKey)
@@ -81,21 +81,30 @@ function applyHooks(model, schema, options) {
81
81
  // promises and make it so that `doc.save.toString()` provides meaningful
82
82
  // information.
83
83
 
84
- const middleware = schema._getDocumentMiddleware();
84
+ const middleware = schema._getDocumentMiddleware(model.prototype.$isSubdocument);
85
85
 
86
86
  model._middleware = middleware;
87
87
 
88
- objToDecorate.$__init = middleware.
89
- createWrapperSync('init', objToDecorate.$__init, null, {
90
- ...kareemOptions,
91
- getOptions: (args) => {
92
- const opts = args[1];
93
- return {
94
- pre: { filter: buildMiddlewareFilter(opts, 'pre') },
95
- post: { filter: buildMiddlewareFilter(opts, 'post') }
96
- };
97
- }
98
- });
88
+ // Most subdocuments have no init hooks. Avoid wrapping every hydration in
89
+ // Kareem when there is no middleware to run.
90
+ const $__init = objToDecorate.$__init;
91
+ if (middleware.hasHooks('init')) {
92
+ objToDecorate.$__init = middleware.
93
+ createWrapperSync('init', $__init, null, {
94
+ ...kareemOptions,
95
+ getOptions: (args) => {
96
+ const opts = args[1];
97
+ return {
98
+ pre: { filter: buildMiddlewareFilter(opts, 'pre') },
99
+ post: { filter: buildMiddlewareFilter(opts, 'post') }
100
+ };
101
+ }
102
+ });
103
+ } else {
104
+ // Still define an own `$__init` so top-level discriminators, whose prototype is later set to
105
+ // the base model's prototype, don't inherit the base model's wrapped `$__init`.
106
+ objToDecorate.$__init = $__init;
107
+ }
99
108
 
100
109
  // Support hooks for custom methods
101
110
  const customMethods = Object.keys(schema.methods);
@@ -6,6 +6,7 @@ const applyTimestampsToChildren = require('../update/applyTimestampsToChildren')
6
6
  const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
7
7
  const cast = require('../../cast');
8
8
  const castUpdate = require('../query/castUpdate');
9
+ const { castArrayFiltersForUpdate } = require('../update/castArrayFilters');
9
10
  const clone = require('../clone');
10
11
  const decorateUpdateWithVersionKey = require('../update/decorateUpdateWithVersionKey');
11
12
  const { inspect } = require('util');
@@ -153,6 +154,10 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
153
154
  strict: strict,
154
155
  upsert: updateOne.upsert
155
156
  });
157
+ if (Array.isArray(updateOne.arrayFilters)) {
158
+ updateOne.arrayFilters = clone(updateOne.arrayFilters);
159
+ castArrayFiltersForUpdate(updateOne.arrayFilters, update, schema, model, options);
160
+ }
156
161
  updateOne['update'] = castUpdate(model.schema, update, {
157
162
  strict: strict,
158
163
  upsert: updateOne.upsert,
@@ -214,6 +219,10 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
214
219
  strict: strict,
215
220
  upsert: updateMany.upsert
216
221
  });
222
+ if (Array.isArray(updateMany.arrayFilters)) {
223
+ updateMany.arrayFilters = clone(updateMany.arrayFilters);
224
+ castArrayFiltersForUpdate(updateMany.arrayFilters, update, schema, model, options);
225
+ }
217
226
 
218
227
  updateMany['update'] = castUpdate(model.schema, update, {
219
228
  strict: strict,
@@ -7,30 +7,53 @@ const updatedPathsByArrayFilter = require('./updatedPathsByArrayFilter');
7
7
  const utils = require('../../utils');
8
8
 
9
9
  module.exports = function castArrayFilters(query) {
10
- const arrayFilters = query.options.arrayFilters;
10
+ castArrayFiltersForUpdate(
11
+ query.options.arrayFilters,
12
+ query.getUpdate(),
13
+ query.schema,
14
+ query.model,
15
+ query._mongooseOptions,
16
+ query
17
+ );
18
+ };
19
+
20
+ /**
21
+ * Casts `arrayFilters` in place against the schema paths that `update` modifies.
22
+ * Shared by queries and `bulkWrite()`.
23
+ *
24
+ * @param {Array} arrayFilters
25
+ * @param {object} update the update that the array filters apply to, before casting
26
+ * @param {Schema} schema
27
+ * @param {Model} [model]
28
+ * @param {object} options the `strict` and `strictQuery` options of the query or bulk write
29
+ * @param {object} [context] passed to `castForQuery()`
30
+ * @api private
31
+ */
32
+
33
+ function castArrayFiltersForUpdate(arrayFilters, update, schema, model, options, context) {
11
34
  if (!Array.isArray(arrayFilters)) {
12
35
  return;
13
36
  }
14
- const update = query.getUpdate();
15
- const schema = query.schema;
16
37
  const updatedPathsByFilter = updatedPathsByArrayFilter(update);
17
38
 
18
39
  let strictQuery = schema.options.strict;
19
- if (query._mongooseOptions.strict != null) {
20
- strictQuery = query._mongooseOptions.strict;
40
+ if (options.strict != null) {
41
+ strictQuery = options.strict;
21
42
  }
22
- if (query.model?.base.options.strictQuery != null) {
23
- strictQuery = query.model.base.options.strictQuery;
43
+ if (model?.base.options.strictQuery != null) {
44
+ strictQuery = model.base.options.strictQuery;
24
45
  }
25
46
  if (schema._userProvidedOptions.strictQuery != null) {
26
47
  strictQuery = schema._userProvidedOptions.strictQuery;
27
48
  }
28
- if (query._mongooseOptions.strictQuery != null) {
29
- strictQuery = query._mongooseOptions.strictQuery;
49
+ if (options.strictQuery != null) {
50
+ strictQuery = options.strictQuery;
30
51
  }
31
52
 
32
- _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilter, query);
33
- };
53
+ _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilter, context);
54
+ }
55
+
56
+ module.exports.castArrayFiltersForUpdate = castArrayFiltersForUpdate;
34
57
 
35
58
  function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilter, query) {
36
59
  // Map to store discriminator values for embedded documents in the array filters.
package/lib/model.js CHANGED
@@ -615,7 +615,7 @@ function generateVersionError(doc, modifiedPaths, defaultPaths) {
615
615
  * newProduct === product; // true
616
616
  *
617
617
  * @param {object} [options] options optional options
618
- * @param {Session} [options.session=null] the [session](https://www.mongodb.com/docs/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](https://mongoosejs.com/docs/api/document.html#Document.prototype.session()).
618
+ * @param {Session} [options.session=null] the [session](https://www.mongodb.com/docs/manual/reference/server-sessions/) associated with this save operation. If not specified, defaults to the [document's associated session](https://mongoosejs.com/docs/api/document.html#Document.prototype.$session()).
619
619
  * @param {object} [options.safe] (DEPRECATED) overrides [schema's safe option](https://mongoosejs.com/docs/guide.html#safe). Use the `w` option instead.
620
620
  * @param {boolean} [options.validateBeforeSave] set to false to save without validating.
621
621
  * @param {boolean} [options.validateModifiedOnly=false] if `true`, Mongoose will only validate modified paths, as opposed to modified paths and `required` paths.
@@ -2391,7 +2391,7 @@ Model.where = function where(path, val) {
2391
2391
  * @method $where
2392
2392
  * @memberOf Model
2393
2393
  * @return {Query}
2394
- * @see Query.$where https://mongoosejs.com/docs/api/query.html#Query.prototype.$where
2394
+ * @see Query.$where https://mongoosejs.com/docs/api/query.html#Query.prototype.$where()
2395
2395
  * @api public
2396
2396
  */
2397
2397
 
package/lib/mongoose.js CHANGED
@@ -240,7 +240,7 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
240
240
  * - `selectPopulatedPaths`: `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
241
241
  * - `strictQuery`: `false` by default. May be `false`, `true`, or `'throw'`. Sets the default [strictQuery](https://mongoosejs.com/docs/guide.html#strictQuery) mode for schemas.
242
242
  * - `strict`: `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
243
- * - `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.immutable) which means you can update the `createdAt`
243
+ * - `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.immutable()) which means you can update the `createdAt`
244
244
  * - `toJSON`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.toJSON()), for determining how Mongoose documents get serialized by `JSON.stringify()`
245
245
  * - `toObject`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.toObject())
246
246
  * - `transactionAsyncLocalStorage`: `false` by default. If `true`, Mongoose will automatically pass the `session` to any operation executing within a transaction executor function. See [transaction AsyncLocalStorage documentation](https://mongoosejs.com/docs/transactions.html#asynclocalstorage)
@@ -1067,7 +1067,7 @@ Mongoose.prototype.Query = Query;
1067
1067
  Mongoose.prototype.Model = Model;
1068
1068
 
1069
1069
  /**
1070
- * The Mongoose [Document](https://mongoosejs.com/docs/api/document.html#Document()) constructor.
1070
+ * The Mongoose [Document](https://mongoosejs.com/docs/api/document.html) constructor.
1071
1071
  *
1072
1072
  * @method Document
1073
1073
  * @api public
@@ -92,6 +92,10 @@ function saveSubdocsPostDeleteOne() {
92
92
 
93
93
 
94
94
  saveSubdocsPreSave[symbols.builtInMiddleware] = true;
95
+ saveSubdocsPreSave[symbols.skipOnSubdocuments] = true;
95
96
  saveSubdocsPostSave[symbols.builtInMiddleware] = true;
97
+ saveSubdocsPostSave[symbols.skipOnSubdocuments] = true;
96
98
  saveSubdocsPreDeleteOne[symbols.builtInMiddleware] = true;
99
+ saveSubdocsPreDeleteOne[symbols.skipOnSubdocuments] = true;
97
100
  saveSubdocsPostDeleteOne[symbols.builtInMiddleware] = true;
101
+ saveSubdocsPostDeleteOne[symbols.skipOnSubdocuments] = true;
@@ -95,7 +95,17 @@ function storeShard() {
95
95
  }
96
96
 
97
97
  shardingPluginPostInit[symbols.builtInMiddleware] = true;
98
+ shardingPluginPostInit[symbols.skipOnSubdocuments] = true;
99
+ shardingPluginPostInit[symbols.requiresShardKey] = true;
98
100
  shardingPluginPreSave[symbols.builtInMiddleware] = true;
101
+ shardingPluginPreSave[symbols.skipOnSubdocuments] = true;
102
+ shardingPluginPreSave[symbols.requiresShardKey] = true;
99
103
  shardingPluginPostSave[symbols.builtInMiddleware] = true;
104
+ shardingPluginPostSave[symbols.skipOnSubdocuments] = true;
105
+ shardingPluginPostSave[symbols.requiresShardKey] = true;
100
106
  shardingPluginPreDeleteOne[symbols.builtInMiddleware] = true;
107
+ shardingPluginPreDeleteOne[symbols.skipOnSubdocuments] = true;
108
+ shardingPluginPreDeleteOne[symbols.requiresShardKey] = true;
101
109
  shardingPluginPreUpdateOne[symbols.builtInMiddleware] = true;
110
+ shardingPluginPreUpdateOne[symbols.skipOnSubdocuments] = true;
111
+ shardingPluginPreUpdateOne[symbols.requiresShardKey] = true;
package/lib/query.js CHANGED
@@ -893,7 +893,7 @@ Query.prototype.mod = function() {
893
893
  *
894
894
  * #### Note:
895
895
  *
896
- * As of Mongoose 3.7, `$geoWithin` is always used for queries. To change this behavior, see [Query.use$geoWithin](https://mongoosejs.com/docs/api/query.html#Query.prototype.use$geoWithin).
896
+ * As of Mongoose 3.7, `$geoWithin` is always used for queries. To change this behavior, see [Query.use$geoWithin](https://mongoosejs.com/docs/api/query.html#Query.use$geoWithin).
897
897
  *
898
898
  * #### Note:
899
899
  *
@@ -4232,7 +4232,7 @@ Query.prototype.validate = async function validate(castedDoc, options, isOverwri
4232
4232
  /**
4233
4233
  * Execute an updateMany query
4234
4234
  *
4235
- * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4235
+ * @see Model.updateMany https://mongoosejs.com/docs/api/model.html#Model.updateMany()
4236
4236
  * @method _updateMany
4237
4237
  * @memberOf Query
4238
4238
  * @instance
@@ -4278,7 +4278,7 @@ Query.prototype._updateMany = async function _updateMany() {
4278
4278
  /**
4279
4279
  * Execute an updateOne query
4280
4280
  *
4281
- * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4281
+ * @see Model.updateOne https://mongoosejs.com/docs/api/model.html#Model.updateOne()
4282
4282
  * @method _updateOne
4283
4283
  * @memberOf Query
4284
4284
  * @instance
@@ -4389,7 +4389,7 @@ Query.prototype._replaceOne = async function _replaceOne() {
4389
4389
  * @param {boolean} [options.overwriteImmutable=false] Mongoose removes updated immutable properties from `update` by default (excluding $setOnInsert). Set `overwriteImmutable` to `true` to allow updating immutable properties using other update operators.
4390
4390
  * @param {boolean} [options.requireFilter=false] If true, throws an error if the filter is empty (`{}`)
4391
4391
  * @return {Query} this
4392
- * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4392
+ * @see Model.updateMany https://mongoosejs.com/docs/api/model.html#Model.updateMany()
4393
4393
  * @see Query docs https://mongoosejs.com/docs/queries.html
4394
4394
  * @see update https://www.mongodb.com/docs/manual/reference/method/db.collection.update/
4395
4395
  * @see UpdateResult https://mongodb.github.io/node-mongodb-native/7.0/interfaces/UpdateResult.html
@@ -4465,7 +4465,7 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) {
4465
4465
  * @param {boolean} [options.overwriteImmutable=false] Mongoose removes updated immutable properties from `update` by default (excluding $setOnInsert). Set `overwriteImmutable` to `true` to allow updating immutable properties using other update operators.
4466
4466
  * @param {boolean} [options.requireFilter=false] If true, throws an error if the filter is empty (`{}`)
4467
4467
  * @return {Query} this
4468
- * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4468
+ * @see Model.updateOne https://mongoosejs.com/docs/api/model.html#Model.updateOne()
4469
4469
  * @see Query docs https://mongoosejs.com/docs/queries.html
4470
4470
  * @see update https://www.mongodb.com/docs/manual/reference/method/db.collection.update/
4471
4471
  * @see UpdateResult https://mongodb.github.io/node-mongodb-native/7.0/interfaces/UpdateResult.html
@@ -4533,7 +4533,7 @@ Query.prototype.updateOne = function(conditions, doc, options, callback) {
4533
4533
  * @param {boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
4534
4534
  * @param {boolean} [options.requireFilter=false] If true, throws an error if the filter is empty (`{}`)
4535
4535
  * @return {Query} this
4536
- * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4536
+ * @see Model.replaceOne https://mongoosejs.com/docs/api/model.html#Model.replaceOne()
4537
4537
  * @see Query docs https://mongoosejs.com/docs/queries.html
4538
4538
  * @see update https://www.mongodb.com/docs/manual/reference/method/db.collection.update/
4539
4539
  * @see UpdateResult https://mongodb.github.io/node-mongodb-native/7.0/interfaces/UpdateResult.html
@@ -222,7 +222,9 @@ SchemaNumber.prototype.min = function(value, message) {
222
222
 
223
223
  if (value != null) {
224
224
  let msg = message || MongooseError.messages.Number.min;
225
- msg = msg.replace(/{MIN}/, value);
225
+ if (typeof msg === 'string') {
226
+ msg = msg.replace(/{MIN}/, value);
227
+ }
226
228
  this.validators.push({
227
229
  validator: this.minValidator = function(v) {
228
230
  return v == null || v >= value;
@@ -276,7 +278,9 @@ SchemaNumber.prototype.max = function(value, message) {
276
278
 
277
279
  if (value != null) {
278
280
  let msg = message || MongooseError.messages.Number.max;
279
- msg = msg.replace(/{MAX}/, value);
281
+ if (typeof msg === 'string') {
282
+ msg = msg.replace(/{MAX}/, value);
283
+ }
280
284
  this.validators.push({
281
285
  validator: this.maxValidator = function(v) {
282
286
  return v == null || v <= value;
@@ -417,7 +417,9 @@ SchemaString.prototype.minlength = function(value, message) {
417
417
 
418
418
  if (value != null) {
419
419
  let msg = message || MongooseError.messages.String.minlength;
420
- msg = msg.replace(/{MINLENGTH}/, value);
420
+ if (typeof msg === 'string') {
421
+ msg = msg.replace(/{MINLENGTH}/, value);
422
+ }
421
423
  this.validators.push({
422
424
  validator: this.minlengthValidator = function(v) {
423
425
  return v === null || v.length >= value;
@@ -3,3 +3,5 @@
3
3
  exports.schemaMixedSymbol = Symbol.for('mongoose:schema_mixed');
4
4
 
5
5
  exports.builtInMiddleware = Symbol.for('mongoose:built-in-middleware');
6
+ exports.skipOnSubdocuments = Symbol('mongoose:skip-on-subdocuments');
7
+ exports.requiresShardKey = Symbol.for('mongoose:requires-shard-key');
package/lib/schema.js CHANGED
@@ -700,9 +700,18 @@ Schema.prototype.discriminator = function(name, schema, options) {
700
700
  /*!
701
701
  * Get the document middleware for this schema, filtering out any hooks that are specific to queries.
702
702
  */
703
- Schema.prototype._getDocumentMiddleware = function _getDocumentMiddleware() {
703
+ Schema.prototype._getDocumentMiddleware = function _getDocumentMiddleware(isSubdocument) {
704
+ // Check `shardKey` at compile time rather than when the sharding plugin is applied, because
705
+ // discriminators apply plugins before inheriting the base schema's options.
706
+ const hasShardKey = !!(this.options.shardKey || this.options.shardkey);
704
707
  return this.s.hooks.
705
708
  filter(hook => {
709
+ if (isSubdocument && hook.fn[symbols.skipOnSubdocuments]) {
710
+ return false;
711
+ }
712
+ if (!hasShardKey && hook.fn[symbols.requiresShardKey]) {
713
+ return false;
714
+ }
706
715
  if (hook.name === 'updateOne' || hook.name === 'deleteOne') {
707
716
  return !!hook['document'];
708
717
  }
package/lib/schemaType.js CHANGED
@@ -645,7 +645,7 @@ SchemaType.prototype.sparse = function(bool) {
645
645
 
646
646
  /**
647
647
  * Defines this path as immutable. Mongoose prevents you from changing
648
- * immutable paths unless the parent document has [`isNew: true`](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew()).
648
+ * immutable paths unless the parent document has [`isNew: true`](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew).
649
649
  *
650
650
  * #### Example:
651
651
  *
@@ -682,7 +682,7 @@ SchemaType.prototype.sparse = function(bool) {
682
682
  *
683
683
  * @param {boolean} bool
684
684
  * @return {SchemaType} this
685
- * @see isNew https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew()
685
+ * @see isNew https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew
686
686
  * @api public
687
687
  */
688
688
 
@@ -1131,7 +1131,7 @@ SchemaType.prototype.validate = function(obj, message, type) {
1131
1131
  * @see SchemaBoolean#checkRequired https://mongoosejs.com/docs/api/schemaboolean.html#SchemaBoolean.prototype.checkRequired()
1132
1132
  * @see SchemaBuffer#checkRequired https://mongoosejs.com/docs/api/schemabuffer.html#SchemaBuffer.prototype.checkRequired()
1133
1133
  * @see SchemaNumber#checkRequired https://mongoosejs.com/docs/api/schemanumber.html#SchemaNumber.prototype.checkRequired()
1134
- * @see SchemaObjectId#checkRequired https://mongoosejs.com/docs/api/schemaobjectid.html#ObjectId.prototype.checkRequired()
1134
+ * @see SchemaObjectId#checkRequired https://mongoosejs.com/docs/api/schemaobjectid.html#SchemaObjectId.prototype.checkRequired()
1135
1135
  * @see SchemaString#checkRequired https://mongoosejs.com/docs/api/schemastring.html#SchemaString.prototype.checkRequired()
1136
1136
  * @api public
1137
1137
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "9.11.1",
4
+ "version": "9.11.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -21,7 +21,7 @@
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
23
  "@standard-schema/spec": "^1.1.0",
24
- "kareem": "3.4.0",
24
+ "kareem": "3.4.1",
25
25
  "mongodb": "~7.7",
26
26
  "mpath": "0.9.0",
27
27
  "mquery": "6.0.0",
@@ -23,7 +23,9 @@ declare module 'mongoose' {
23
23
  ? { [K in keyof T]: PopulatePathToRawDocType<T[K]> }
24
24
  : T;
25
25
 
26
- type PopulatedPathsDocumentType<RawDocType, Paths> = UnpackedIntersection<RawDocType, PopulatePathToRawDocType<Paths>>;
26
+ type PopulatedPathsDocumentType<RawDocType, Paths> = Paths extends Record<string, never>
27
+ ? RawDocType
28
+ : UnpackedIntersection<RawDocType, PopulatePathToRawDocType<Paths>>;
27
29
 
28
30
  type PopulatedDocumentMarker<
29
31
  PopulatedRawDocType,
@@ -193,18 +193,18 @@ declare module 'mongoose' {
193
193
  min?:
194
194
  | number
195
195
  | NativeDate
196
- | [number, string]
196
+ | [number, string | ValidatorMessageFn]
197
197
  | [NativeDate, string]
198
- | readonly [number, string]
198
+ | readonly [number, string | ValidatorMessageFn]
199
199
  | readonly [NativeDate, string];
200
200
 
201
201
  /** The maximum value allowed for this path. Only allowed for numbers and dates. */
202
202
  max?:
203
203
  | number
204
204
  | NativeDate
205
- | [number, string]
205
+ | [number, string | ValidatorMessageFn]
206
206
  | [NativeDate, string]
207
- | readonly [number, string]
207
+ | readonly [number, string | ValidatorMessageFn]
208
208
  | readonly [NativeDate, string];
209
209
 
210
210
  /** Set to false to disable minimizing empty single nested subdocuments by default */
@@ -241,12 +241,12 @@ declare module 'mongoose' {
241
241
  uppercase?: boolean;
242
242
 
243
243
  /** If set, Mongoose will add a custom validator that ensures the given string's `length` is at least the given number. */
244
- minlength?: number | [number, string] | readonly [number, string];
245
- minLength?: number | [number, string] | readonly [number, string];
244
+ minlength?: number | [number, string | ValidatorMessageFn] | readonly [number, string | ValidatorMessageFn];
245
+ minLength?: number | [number, string | ValidatorMessageFn] | readonly [number, string | ValidatorMessageFn];
246
246
 
247
247
  /** If set, Mongoose will add a custom validator that ensures the given string's `length` is at most the given number. */
248
- maxlength?: number | [number, string] | readonly [number, string];
249
- maxLength?: number | [number, string] | readonly [number, string];
248
+ maxlength?: number | [number, string | ValidatorMessageFn] | readonly [number, string | ValidatorMessageFn];
249
+ maxLength?: number | [number, string | ValidatorMessageFn] | readonly [number, string | ValidatorMessageFn];
250
250
 
251
251
  [other: string]: any;
252
252
 
@@ -562,10 +562,10 @@ declare module 'mongoose' {
562
562
  enum(vals: number[]): this;
563
563
 
564
564
  /** Sets a maximum number validator. */
565
- max(value: number, message?: string): this;
565
+ max(value: number, message?: string | ValidatorMessageFn): this;
566
566
 
567
567
  /** Sets a minimum number validator. */
568
- min(value: number, message?: string): this;
568
+ min(value: number, message?: string | ValidatorMessageFn): this;
569
569
 
570
570
  /** Default options for this SchemaType */
571
571
  static defaultOptions: Record<string, any>;
@@ -632,10 +632,10 @@ declare module 'mongoose' {
632
632
  match(value: RegExp, message: string): this;
633
633
 
634
634
  /** Sets a maximum length validator. */
635
- maxlength(value: number, message: string): this;
635
+ maxlength(value: number, message: string | ValidatorMessageFn): this;
636
636
 
637
637
  /** Sets a minimum length validator. */
638
- minlength(value: number, message: string): this;
638
+ minlength(value: number, message: string | ValidatorMessageFn): this;
639
639
 
640
640
  /** Adds a trim [setter](http://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-set). */
641
641
  trim(shouldTrim?: boolean): this;
@@ -143,7 +143,13 @@ declare module 'mongoose' {
143
143
  ? T
144
144
  : T extends any ? (Omit<T, keyof U> & U) : never;
145
145
 
146
- type MergeType<A, B> = A extends unknown ? Omit<A, keyof B> & B : never;
146
+ type MergeTypeKeys<T> = T extends unknown ? keyof T : never;
147
+
148
+ type MergeType<A, B> = [B] extends [object]
149
+ ? [MergeTypeKeys<B>] extends [never]
150
+ ? A
151
+ : A extends unknown ? Omit<A, keyof B> & B : never
152
+ : A extends unknown ? Omit<A, keyof B> & B : never;
147
153
 
148
154
  /**
149
155
  * @summary Converts Unions to one record "object".