mongoose 8.9.0 → 8.9.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/query.js CHANGED
@@ -2247,10 +2247,7 @@ Query.prototype.error = function error(err) {
2247
2247
  */
2248
2248
 
2249
2249
  Query.prototype._unsetCastError = function _unsetCastError() {
2250
- if (this._error == null) {
2251
- return;
2252
- }
2253
- if (this._error != null && !(this._error instanceof CastError)) {
2250
+ if (this._error == null || !(this._error instanceof CastError)) {
2254
2251
  return;
2255
2252
  }
2256
2253
  return this.error(null);
@@ -3197,7 +3194,6 @@ Query.prototype.deleteMany = function(filter, options) {
3197
3194
  /**
3198
3195
  * Execute a `deleteMany()` query
3199
3196
  *
3200
- * @param {Function} callback
3201
3197
  * @method _deleteMany
3202
3198
  * @instance
3203
3199
  * @memberOf Query
@@ -3490,13 +3486,6 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
3490
3486
  * - `sort`: if multiple docs are found by the conditions, sets the sort order to choose which doc to update
3491
3487
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
3492
3488
  *
3493
- * #### Callback Signature
3494
- *
3495
- * function(error, doc) {
3496
- * // error: any errors that occurred
3497
- * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
3498
- * }
3499
- *
3500
3489
  * #### Example:
3501
3490
  *
3502
3491
  * A.where().findOneAndDelete(conditions, options) // return Query
@@ -3587,13 +3576,6 @@ Query.prototype._findOneAndDelete = async function _findOneAndDelete() {
3587
3576
  * - `maxTimeMS`: puts a time limit on the query - requires mongodb >= 2.6.0
3588
3577
  * - `includeResultMetadata`: if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html) rather than just the document
3589
3578
  *
3590
- * #### Callback Signature
3591
- *
3592
- * function(error, doc) {
3593
- * // error: any errors that occurred
3594
- * // doc: the document before updates are applied if `new: false`, or after updates if `new = true`
3595
- * }
3596
- *
3597
3579
  * #### Example:
3598
3580
  *
3599
3581
  * A.where().findOneAndReplace(filter, replacement, options); // return Query
@@ -4025,7 +4007,6 @@ Query.prototype._replaceOne = async function _replaceOne() {
4025
4007
  * @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.
4026
4008
  * @param {Boolean} [options.overwriteDiscriminatorKey=false] Mongoose removes discriminator key updates from `update` by default, set `overwriteDiscriminatorKey` to `true` to allow updating the discriminator key
4027
4009
  * @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.
4028
- * @param {Function} [callback] params are (error, writeOpResult)
4029
4010
  * @return {Query} this
4030
4011
  * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4031
4012
  * @see Query docs https://mongoosejs.com/docs/queries.html
@@ -4096,7 +4077,6 @@ Query.prototype.updateMany = function(conditions, doc, options, callback) {
4096
4077
  * @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.
4097
4078
  * @param {Boolean} [options.overwriteDiscriminatorKey=false] Mongoose removes discriminator key updates from `update` by default, set `overwriteDiscriminatorKey` to `true` to allow updating the discriminator key
4098
4079
  * @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.
4099
- * @param {Function} [callback] params are (error, writeOpResult)
4100
4080
  * @return {Query} this
4101
4081
  * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4102
4082
  * @see Query docs https://mongoosejs.com/docs/queries.html
@@ -4163,7 +4143,6 @@ Query.prototype.updateOne = function(conditions, doc, options, callback) {
4163
4143
  * @param {Object} [options.writeConcern=null] sets the [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/) for replica sets. Overrides the [schema-level write concern](https://mongoosejs.com/docs/guide.html#writeConcern)
4164
4144
  * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Does nothing if schema-level timestamps are not set.
4165
4145
  * @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.
4166
- * @param {Function} [callback] params are (error, writeOpResult)
4167
4146
  * @return {Query} this
4168
4147
  * @see Model.update https://mongoosejs.com/docs/api/model.html#Model.update()
4169
4148
  * @see Query docs https://mongoosejs.com/docs/queries.html
@@ -181,11 +181,11 @@ SchemaString.checkRequired = SchemaType.checkRequired;
181
181
  * const s = new Schema({ state: { type: String, enum: states }})
182
182
  * const M = db.model('M', s)
183
183
  * const m = new M({ state: 'invalid' })
184
- * m.save(function (err) {
185
- * console.error(String(err)) // ValidationError: `invalid` is not a valid enum value for path `state`.
186
- * m.state = 'open'
187
- * m.save(callback) // success
188
- * })
184
+ * await m.save()
185
+ * .catch((err) => console.error(err)); // ValidationError: `invalid` is not a valid enum value for path `state`.
186
+ * m.state = 'open';
187
+ * await m.save();
188
+ * // success
189
189
  *
190
190
  * // or with custom error messages
191
191
  * const enum = {
@@ -195,11 +195,11 @@ SchemaString.checkRequired = SchemaType.checkRequired;
195
195
  * const s = new Schema({ state: { type: String, enum: enum })
196
196
  * const M = db.model('M', s)
197
197
  * const m = new M({ state: 'invalid' })
198
- * m.save(function (err) {
199
- * console.error(String(err)) // ValidationError: enum validator failed for path `state` with value `invalid`
200
- * m.state = 'open'
201
- * m.save(callback) // success
202
- * })
198
+ * await m.save()
199
+ * .catch((err) => console.error(err)); // ValidationError: enum validator failed for path `state` with value `invalid`
200
+ * m.state = 'open';
201
+ * await m.save();
202
+ * // success
203
203
  *
204
204
  * @param {...String|Object} [args] enumeration values
205
205
  * @return {SchemaType} this
package/lib/schema.js CHANGED
@@ -18,13 +18,13 @@ const getConstructorName = require('./helpers/getConstructorName');
18
18
  const getIndexes = require('./helpers/schema/getIndexes');
19
19
  const handleReadPreferenceAliases = require('./helpers/query/handleReadPreferenceAliases');
20
20
  const idGetter = require('./helpers/schema/idGetter');
21
+ const isIndexSpecEqual = require('./helpers/indexes/isIndexSpecEqual');
21
22
  const merge = require('./helpers/schema/merge');
22
23
  const mpath = require('mpath');
23
24
  const setPopulatedVirtualValue = require('./helpers/populate/setPopulatedVirtualValue');
24
25
  const setupTimestamps = require('./helpers/timestamps/setupTimestamps');
25
26
  const utils = require('./utils');
26
27
  const validateRef = require('./helpers/populate/validateRef');
27
- const util = require('util');
28
28
 
29
29
  const hasNumericSubpathRegex = /\.\d+(\.|$)/;
30
30
 
@@ -441,7 +441,7 @@ Schema.prototype._clone = function _clone(Constructor) {
441
441
  }
442
442
  }
443
443
  }
444
- s.childSchemas = gatherChildSchemas(s);
444
+ s._gatherChildSchemas();
445
445
 
446
446
  s.virtuals = clone(this.virtuals);
447
447
  s.$globalPluginsApplied = this.$globalPluginsApplied;
@@ -899,7 +899,7 @@ Schema.prototype.removeIndex = function removeIndex(index) {
899
899
 
900
900
  if (typeof index === 'object') {
901
901
  for (let i = this._indexes.length - 1; i >= 0; --i) {
902
- if (util.isDeepStrictEqual(this._indexes[i][0], index)) {
902
+ if (isIndexSpecEqual(this._indexes[i][0], index)) {
903
903
  this._indexes.splice(i, 1);
904
904
  }
905
905
  }
@@ -1238,20 +1238,32 @@ Schema.prototype.path = function(path, obj) {
1238
1238
  * ignore
1239
1239
  */
1240
1240
 
1241
- function gatherChildSchemas(schema) {
1241
+ Schema.prototype._gatherChildSchemas = function _gatherChildSchemas() {
1242
1242
  const childSchemas = [];
1243
1243
 
1244
- for (const path of Object.keys(schema.paths)) {
1245
- const schematype = schema.paths[path];
1244
+ for (const path of Object.keys(this.paths)) {
1245
+ if (typeof path !== 'string') {
1246
+ continue;
1247
+ }
1248
+ const schematype = this.paths[path];
1246
1249
  if (schematype.$isMongooseDocumentArray || schematype.$isSingleNested) {
1247
- childSchemas.push({ schema: schematype.schema, model: schematype.caster, path: path });
1250
+ childSchemas.push({
1251
+ schema: schematype.schema,
1252
+ model: schematype.caster,
1253
+ path: path
1254
+ });
1248
1255
  } else if (schematype.$isSchemaMap && schematype.$__schemaType.$isSingleNested) {
1249
- childSchemas.push({ schema: schematype.$__schemaType.schema, model: schematype.$__schemaType.caster, path: path });
1256
+ childSchemas.push({
1257
+ schema: schematype.$__schemaType.schema,
1258
+ model: schematype.$__schemaType.caster,
1259
+ path: path
1260
+ });
1250
1261
  }
1251
1262
  }
1252
1263
 
1264
+ this.childSchemas = childSchemas;
1253
1265
  return childSchemas;
1254
- }
1266
+ };
1255
1267
 
1256
1268
  /*!
1257
1269
  * ignore
@@ -2134,6 +2146,12 @@ Schema.prototype.index = function(fields, options) {
2134
2146
  }
2135
2147
  }
2136
2148
 
2149
+ for (const existingIndex of this.indexes()) {
2150
+ if (options.name == null && existingIndex[1].name == null && isIndexSpecEqual(existingIndex[0], fields)) {
2151
+ throw new MongooseError(`Schema already has an index on ${JSON.stringify(fields)}`);
2152
+ }
2153
+ }
2154
+
2137
2155
  this._indexes.push([fields, options]);
2138
2156
  return this;
2139
2157
  };
package/lib/types/map.js CHANGED
@@ -9,6 +9,7 @@ const handleSpreadDoc = require('../helpers/document/handleSpreadDoc');
9
9
  const util = require('util');
10
10
  const specialProperties = require('../helpers/specialProperties');
11
11
  const isBsonType = require('../helpers/isBsonType');
12
+ const cleanModifiedSubpaths = require('../helpers/document/cleanModifiedSubpaths');
12
13
 
13
14
  const populateModelSymbol = require('../helpers/symbols').populateModelSymbol;
14
15
 
@@ -157,7 +158,13 @@ class MongooseMap extends Map {
157
158
  super.set(key, value);
158
159
 
159
160
  if (parent != null && parent.$__ != null && !deepEqual(value, priorVal)) {
160
- parent.markModified(fullPath.call(this));
161
+ const path = fullPath.call(this);
162
+ parent.markModified(path);
163
+ // If overwriting the full document array or subdoc, make sure to clean up any paths that were modified
164
+ // before re: #15108
165
+ if (this.$__schemaType.$isMongooseDocumentArray || this.$__schemaType.$isSingleNested) {
166
+ cleanModifiedSubpaths(parent, path);
167
+ }
161
168
  }
162
169
 
163
170
  // Delay calculating full path unless absolutely necessary, because string
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "8.9.0",
4
+ "version": "8.9.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -30,8 +30,8 @@
30
30
  "devDependencies": {
31
31
  "@babel/core": "7.26.0",
32
32
  "@babel/preset-env": "7.26.0",
33
- "@typescript-eslint/eslint-plugin": "^8.4.0",
34
- "@typescript-eslint/parser": "^8.4.0",
33
+ "@typescript-eslint/eslint-plugin": "^8.18.0",
34
+ "@typescript-eslint/parser": "^8.18.0",
35
35
  "acquit": "1.3.0",
36
36
  "acquit-ignore": "0.2.1",
37
37
  "acquit-require": "0.1.1",
package/types/index.d.ts CHANGED
@@ -572,7 +572,8 @@ declare module 'mongoose' {
572
572
  | typeof Schema.Types.Number
573
573
  | typeof Schema.Types.String
574
574
  | typeof Schema.Types.Buffer
575
- | typeof Schema.Types.ObjectId;
575
+ | typeof Schema.Types.ObjectId
576
+ | typeof Schema.Types.UUID;
576
577
 
577
578
 
578
579
  export type InferId<T> = T extends { _id?: any } ? T['_id'] : Types.ObjectId;
@@ -712,76 +713,82 @@ declare module 'mongoose' {
712
713
  /**
713
714
  * Converts any Buffer properties into mongodb.Binary instances, which is what `lean()` returns
714
715
  */
715
- export type BufferToBinary<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
716
- [K in keyof T]: T[K] extends Buffer
717
- ? mongodb.Binary
718
- : T[K] extends (Buffer | null | undefined)
719
- ? mongodb.Binary | null | undefined
720
- : T[K] extends Types.DocumentArray<infer ItemType>
716
+ export type BufferToBinary<T> = T extends Buffer
717
+ ? mongodb.Binary
718
+ : T extends TreatAsPrimitives
719
+ ? T
720
+ : T extends Record<string, any> ? {
721
+ [K in keyof T]: T[K] extends Buffer
722
+ ? mongodb.Binary
723
+ : T[K] extends Types.DocumentArray<infer ItemType>
721
724
  ? Types.DocumentArray<BufferToBinary<ItemType>>
722
725
  : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
723
726
  ? HydratedSingleSubdocument<SubdocType>
724
727
  : BufferToBinary<T[K]>;
725
- } : T;
728
+ } : T;
726
729
 
727
730
  /**
728
731
  * Converts any Buffer properties into { type: 'buffer', data: [1, 2, 3] } format for JSON serialization
729
732
  */
730
- export type BufferToJSON<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
731
- [K in keyof T]: T[K] extends Buffer
732
- ? { type: 'buffer', data: number[] }
733
- : T[K] extends (Buffer | null | undefined)
734
- ? { type: 'buffer', data: number[] } | null | undefined
735
- : T[K] extends Types.DocumentArray<infer ItemType>
736
- ? Types.DocumentArray<BufferToBinary<ItemType>>
737
- : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
738
- ? HydratedSingleSubdocument<SubdocType>
739
- : BufferToBinary<T[K]>;
740
- } : T;
733
+ export type BufferToJSON<T> = T extends Buffer
734
+ ? { type: 'buffer', data: number[] }
735
+ : T extends TreatAsPrimitives
736
+ ? T
737
+ : T extends Record<string, any> ? {
738
+ [K in keyof T]: T[K] extends Buffer
739
+ ? { type: 'buffer', data: number[] }
740
+ : T[K] extends Types.DocumentArray<infer ItemType>
741
+ ? Types.DocumentArray<BufferToBinary<ItemType>>
742
+ : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
743
+ ? HydratedSingleSubdocument<SubdocType>
744
+ : BufferToBinary<T[K]>;
745
+ } : T;
741
746
 
742
747
  /**
743
748
  * Converts any ObjectId properties into strings for JSON serialization
744
749
  */
745
- export type ObjectIdToString<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
746
- [K in keyof T]: T[K] extends mongodb.ObjectId
747
- ? string
748
- : T[K] extends (mongodb.ObjectId | null | undefined)
749
- ? string | null | undefined
750
- : T[K] extends Types.DocumentArray<infer ItemType>
751
- ? Types.DocumentArray<ObjectIdToString<ItemType>>
752
- : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
753
- ? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
754
- : ObjectIdToString<T[K]>;
755
- } : T;
750
+ export type ObjectIdToString<T> = T extends mongodb.ObjectId
751
+ ? string
752
+ : T extends TreatAsPrimitives
753
+ ? T
754
+ : T extends Record<string, any> ? {
755
+ [K in keyof T]: T[K] extends mongodb.ObjectId
756
+ ? string
757
+ : T[K] extends Types.DocumentArray<infer ItemType>
758
+ ? Types.DocumentArray<ObjectIdToString<ItemType>>
759
+ : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
760
+ ? HydratedSingleSubdocument<ObjectIdToString<SubdocType>>
761
+ : ObjectIdToString<T[K]>;
762
+ } : T;
756
763
 
757
764
  /**
758
765
  * Converts any Date properties into strings for JSON serialization
759
766
  */
760
- export type DateToString<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
761
- [K in keyof T]: T[K] extends NativeDate
762
- ? string
763
- : T[K] extends (NativeDate | null | undefined)
764
- ? string | null | undefined
765
- : T[K] extends Types.DocumentArray<infer ItemType>
766
- ? Types.DocumentArray<DateToString<ItemType>>
767
- : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
768
- ? HydratedSingleSubdocument<DateToString<SubdocType>>
769
- : DateToString<T[K]>;
770
- } : T;
767
+ export type DateToString<T> = T extends NativeDate
768
+ ? string
769
+ : T extends TreatAsPrimitives
770
+ ? T
771
+ : T extends Record<string, any> ? {
772
+ [K in keyof T]: T[K] extends NativeDate
773
+ ? string
774
+ : T[K] extends (NativeDate | null | undefined)
775
+ ? string | null | undefined
776
+ : T[K] extends Types.DocumentArray<infer ItemType>
777
+ ? Types.DocumentArray<DateToString<ItemType>>
778
+ : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
779
+ ? HydratedSingleSubdocument<DateToString<SubdocType>>
780
+ : DateToString<T[K]>;
781
+ } : T;
771
782
 
772
783
  /**
773
784
  * Converts any Mongoose subdocuments (single nested or doc arrays) into POJO equivalents
774
785
  */
775
786
  export type SubdocsToPOJOs<T> = T extends TreatAsPrimitives ? T : T extends Record<string, any> ? {
776
- [K in keyof T]: T[K] extends NativeDate
777
- ? string
778
- : T[K] extends (NativeDate | null | undefined)
779
- ? string | null | undefined
780
- : T[K] extends Types.DocumentArray<infer ItemType>
781
- ? ItemType[]
782
- : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
783
- ? SubdocType
784
- : SubdocsToPOJOs<T[K]>;
787
+ [K in keyof T]: T[K] extends Types.DocumentArray<infer ItemType>
788
+ ? ItemType[]
789
+ : T[K] extends Types.Subdocument<unknown, unknown, infer SubdocType>
790
+ ? SubdocType
791
+ : SubdocsToPOJOs<T[K]>;
785
792
  } : T;
786
793
 
787
794
  export type JSONSerialized<T> = SubdocsToPOJOs<