mongoose 7.5.0 → 7.5.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/document.js CHANGED
@@ -1060,6 +1060,10 @@ Document.prototype.$set = function $set(path, val, type, options) {
1060
1060
  [path, val] = [val, path];
1061
1061
  }
1062
1062
 
1063
+ if ('_id' in path && 'id' in path) {
1064
+ delete path.id;
1065
+ }
1066
+
1063
1067
  prefix = val ? val + '.' : '';
1064
1068
  keys = getKeysInSchemaOrder(this.$__schema, path);
1065
1069
 
@@ -3918,7 +3922,7 @@ Document.prototype.$toObject = function(options, json) {
3918
3922
  *
3919
3923
  * @param {Object} [options]
3920
3924
  * @param {Boolean} [options.getters=false] if true, apply all getters, including virtuals
3921
- * @param {Boolean} [options.virtuals=false] if true, apply virtuals, including aliases. Use `{ getters: true, virtuals: false }` to just apply getters, not virtuals
3925
+ * @param {Boolean|Object} [options.virtuals=false] if true, apply virtuals, including aliases. Use `{ getters: true, virtuals: false }` to just apply getters, not virtuals. An object of the form `{ pathsToSkip: ['someVirtual'] }` may also be used to omit specific virtuals.
3922
3926
  * @param {Boolean} [options.aliases=true] if `options.virtuals = true`, you can set `options.aliases = false` to skip applying aliases. This option is a no-op if `options.virtuals = false`.
3923
3927
  * @param {Boolean} [options.minimize=true] if true, omit any empty objects from the output
3924
3928
  * @param {Function|null} [options.transform=null] if set, mongoose will call this function to allow you to transform the returned object
@@ -38,7 +38,9 @@ module.exports = function markArraySubdocsPopulated(doc, populated) {
38
38
 
39
39
  if (utils.isMongooseDocumentArray(val)) {
40
40
  for (let j = 0; j < val.length; ++j) {
41
- val[j].populated(rest, item._docs[id] == null ? void 0 : item._docs[id][j], item);
41
+ if (val[j]) {
42
+ val[j].populated(rest, item._docs[id] == null ? void 0 : item._docs[id][j], item);
43
+ }
42
44
  }
43
45
  break;
44
46
  }
@@ -75,7 +75,11 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
75
75
  continue;
76
76
  }
77
77
 
78
- const discriminatorSchema = getDiscriminatorByValue(schematype.caster.discriminators, discriminatorKey).schema;
78
+ const discriminator = getDiscriminatorByValue(schematype.caster.discriminators, discriminatorKey);
79
+ const discriminatorSchema = discriminator && discriminator.schema;
80
+ if (discriminatorSchema == null) {
81
+ continue;
82
+ }
79
83
 
80
84
  const rest = parts.slice(i + 1).join('.');
81
85
  schematype = discriminatorSchema.path(rest);
package/lib/index.js CHANGED
@@ -624,8 +624,8 @@ Mongoose.prototype._model = function(name, schema, collection, options) {
624
624
  connection.emit('model', model);
625
625
 
626
626
  if (schema._applyDiscriminators != null) {
627
- for (const disc of Object.keys(schema._applyDiscriminators)) {
628
- model.discriminator(disc, schema._applyDiscriminators[disc]);
627
+ for (const disc of schema._applyDiscriminators.keys()) {
628
+ model.discriminator(disc, schema._applyDiscriminators.get(disc));
629
629
  }
630
630
  }
631
631
 
package/lib/model.js CHANGED
@@ -1451,6 +1451,17 @@ Model.createCollection = async function createCollection(options) {
1451
1451
  * // Will drop the 'age' index and create an index on `name`
1452
1452
  * await Customer.syncIndexes();
1453
1453
  *
1454
+ * You should be careful about running `syncIndexes()` on production applications under heavy load,
1455
+ * because index builds are expensive operations, and unexpected index drops can lead to degraded
1456
+ * performance. Before running `syncIndexes()`, you can use the [`diffIndexes()` function](#Model.diffIndexes())
1457
+ * to check what indexes `syncIndexes()` will drop and create.
1458
+ *
1459
+ * #### Example:
1460
+ *
1461
+ * const { toDrop, toCreate } = await Model.diffIndexes();
1462
+ * toDrop; // Array of strings containing names of indexes that `syncIndexes()` will drop
1463
+ * toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create
1464
+ *
1454
1465
  * @param {Object} [options] options to pass to `ensureIndexes()`
1455
1466
  * @param {Boolean} [options.background=null] if specified, overrides each index's `background` property
1456
1467
  * @return {Promise}
@@ -1483,9 +1494,14 @@ Model.syncIndexes = async function syncIndexes(options) {
1483
1494
  /**
1484
1495
  * Does a dry-run of `Model.syncIndexes()`, returning the indexes that `syncIndexes()` would drop and create if you were to run `syncIndexes()`.
1485
1496
  *
1497
+ * #### Example:
1498
+ *
1499
+ * const { toDrop, toCreate } = await Model.diffIndexes();
1500
+ * toDrop; // Array of strings containing names of indexes that `syncIndexes()` will drop
1501
+ * toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create
1502
+ *
1486
1503
  * @param {Object} [options]
1487
- * @returns {Promise} which contains an object, {toDrop, toCreate}, which
1488
- * are indexes that would be dropped in MongoDB and indexes that would be created in MongoDB.
1504
+ * @return {Promise<Object>} contains the indexes that would be dropped in MongoDB and indexes that would be created in MongoDB as `{ toDrop: string[], toCreate: string[] }`.
1489
1505
  */
1490
1506
 
1491
1507
  Model.diffIndexes = async function diffIndexes() {
@@ -2391,7 +2407,7 @@ Model.$where = function $where() {
2391
2407
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
2392
2408
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
2393
2409
  * @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. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
2394
- * @param {Boolean} [options.overwrite=false] By default, if you don't include any [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/) in `update`, Mongoose will wrap `update` in `$set` for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding `$set`. An alternative to this would be using [Model.findOneAndReplace(conditions, update, options, callback)](https://mongoosejs.com/docs/api/model.html#Model.findOneAndReplace()).
2410
+ * @param {Boolean} [options.overwrite=false] If set to `true`, Mongoose will convert this `findOneAndUpdate()` to a `findOneAndReplace()`. This option is deprecated and only supported for backwards compatiblity.
2395
2411
  * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
2396
2412
  * @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select())
2397
2413
  * @param {Boolean} [options.new=false] if true, return the modified document rather than the original
@@ -2512,7 +2528,7 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
2512
2528
  * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
2513
2529
  * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
2514
2530
  * @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. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
2515
- * @param {Boolean} [options.overwrite=false] By default, if you don't include any [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/) in `update`, Mongoose will wrap `update` in `$set` for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding `$set`. An alternative to this would be using [Model.findOneAndReplace({ _id: id }, update, options)](https://mongoosejs.com/docs/api/model.html#Model.findOneAndReplace()).
2531
+ * @param {Boolean} [options.overwrite=false] If set to `true`, Mongoose will convert this `findByIdAndUpdate()` to a `findByIdAndReplace()`. This option is deprecated and only supported for backwards compatiblity.
2516
2532
  * @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
2517
2533
  * @param {Boolean} [options.runValidators] if true, runs [update validators](https://mongoosejs.com/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema
2518
2534
  * @param {Boolean} [options.setDefaultsOnInsert=true] If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created
package/lib/query.js CHANGED
@@ -3819,13 +3819,14 @@ function _completeManyLean(schema, docs, path, opts) {
3819
3819
  */
3820
3820
 
3821
3821
  Query.prototype._mergeUpdate = function(doc) {
3822
+ if (!this._update) {
3823
+ this._update = Array.isArray(doc) ? [] : {};
3824
+ }
3825
+
3822
3826
  if (doc == null || (typeof doc === 'object' && Object.keys(doc).length === 0)) {
3823
3827
  return;
3824
3828
  }
3825
3829
 
3826
- if (!this._update) {
3827
- this._update = Array.isArray(doc) ? [] : {};
3828
- }
3829
3830
  if (doc instanceof Query) {
3830
3831
  if (Array.isArray(this._update)) {
3831
3832
  throw new Error('Cannot mix array and object updates');
package/lib/schema.js CHANGED
@@ -449,7 +449,7 @@ Schema.prototype._clone = function _clone(Constructor) {
449
449
  s.discriminators = Object.assign({}, this.discriminators);
450
450
  }
451
451
  if (this._applyDiscriminators != null) {
452
- s._applyDiscriminators = Object.assign({}, this._applyDiscriminators);
452
+ s._applyDiscriminators = new Map(this._applyDiscriminators);
453
453
  }
454
454
 
455
455
  s.aliases = Object.assign({}, this.aliases);
@@ -621,7 +621,8 @@ Schema.prototype.defaultOptions = function(options) {
621
621
  * @api public
622
622
  */
623
623
  Schema.prototype.discriminator = function(name, schema) {
624
- this._applyDiscriminators = Object.assign(this._applyDiscriminators || {}, { [name]: schema });
624
+ this._applyDiscriminators = this._applyDiscriminators || new Map();
625
+ this._applyDiscriminators.set(name, schema);
625
626
 
626
627
  return this;
627
628
  };
@@ -722,18 +723,18 @@ Schema.prototype.add = function add(obj, prefix) {
722
723
  for (const key in val[0].discriminators) {
723
724
  schemaType.discriminator(key, val[0].discriminators[key]);
724
725
  }
725
- } else if (val[0] != null && val[0].instanceOfSchema && utils.isPOJO(val[0]._applyDiscriminators)) {
726
- const applyDiscriminators = val[0]._applyDiscriminators || [];
726
+ } else if (val[0] != null && val[0].instanceOfSchema && val[0]._applyDiscriminators instanceof Map) {
727
+ const applyDiscriminators = val[0]._applyDiscriminators;
727
728
  const schemaType = this.path(prefix + key);
728
- for (const disc in applyDiscriminators) {
729
- schemaType.discriminator(disc, applyDiscriminators[disc]);
729
+ for (const disc of applyDiscriminators.keys()) {
730
+ schemaType.discriminator(disc, applyDiscriminators.get(disc));
730
731
  }
731
732
  }
732
- else if (val != null && val.instanceOfSchema && utils.isPOJO(val._applyDiscriminators)) {
733
- const applyDiscriminators = val._applyDiscriminators || [];
733
+ else if (val != null && val.instanceOfSchema && val._applyDiscriminators instanceof Map) {
734
+ const applyDiscriminators = val._applyDiscriminators;
734
735
  const schemaType = this.path(prefix + key);
735
- for (const disc in applyDiscriminators) {
736
- schemaType.discriminator(disc, applyDiscriminators[disc]);
736
+ for (const disc of applyDiscriminators.keys()) {
737
+ schemaType.discriminator(disc, applyDiscriminators.get(disc));
737
738
  }
738
739
  }
739
740
  } else if (Object.keys(val).length < 1) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "7.5.0",
4
+ "version": "7.5.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -28,8 +28,8 @@
28
28
  "sift": "16.0.1"
29
29
  },
30
30
  "devDependencies": {
31
- "@babel/core": "7.22.9",
32
- "@babel/preset-env": "7.22.9",
31
+ "@babel/core": "7.22.11",
32
+ "@babel/preset-env": "7.22.14",
33
33
  "@typescript-eslint/eslint-plugin": "5.61.0",
34
34
  "@typescript-eslint/parser": "5.62.0",
35
35
  "acquit": "1.3.0",
@@ -46,7 +46,7 @@
46
46
  "crypto-browserify": "3.12.0",
47
47
  "dotenv": "16.3.1",
48
48
  "dox": "1.0.0",
49
- "eslint": "8.46.0",
49
+ "eslint": "8.48.0",
50
50
  "eslint-plugin-markdown": "^3.0.0",
51
51
  "eslint-plugin-mocha-no-only": "1.1.1",
52
52
  "express": "^4.18.1",
@@ -54,20 +54,20 @@
54
54
  "highlight.js": "11.8.0",
55
55
  "lodash.isequal": "4.5.0",
56
56
  "lodash.isequalwith": "4.4.0",
57
- "markdownlint-cli2": "^0.8.1",
57
+ "markdownlint-cli2": "^0.9.2",
58
58
  "marked": "4.3.0",
59
59
  "mkdirp": "^3.0.1",
60
60
  "mocha": "10.2.0",
61
61
  "moment": "2.x",
62
- "mongodb-memory-server": "8.13.0",
62
+ "mongodb-memory-server": "8.15.1",
63
63
  "ncp": "^2.0.0",
64
64
  "nyc": "15.1.0",
65
65
  "pug": "3.0.2",
66
66
  "q": "1.5.1",
67
67
  "sinon": "15.2.0",
68
68
  "stream-browserify": "3.0.0",
69
- "tsd": "0.28.1",
70
- "typescript": "5.1.6",
69
+ "tsd": "0.29.0",
70
+ "typescript": "5.2.2",
71
71
  "uuid": "9.0.0",
72
72
  "webpack": "5.88.2"
73
73
  },
package/types/index.d.ts CHANGED
@@ -236,7 +236,7 @@ declare module 'mongoose' {
236
236
  /**
237
237
  * Create a new schema
238
238
  */
239
- constructor(definition?: SchemaDefinition<SchemaDefinitionType<EnforcedDocType>> | DocType, options?: SchemaOptions<DocType, TInstanceMethods, TQueryHelpers, TStaticMethods, TVirtuals, THydratedDocumentType> | ResolveSchemaOptions<TSchemaOptions>);
239
+ constructor(definition?: SchemaDefinition<SchemaDefinitionType<EnforcedDocType>, EnforcedDocType> | DocType, options?: SchemaOptions<DocType, TInstanceMethods, TQueryHelpers, TStaticMethods, TVirtuals, THydratedDocumentType> | ResolveSchemaOptions<TSchemaOptions>);
240
240
 
241
241
  /** Adds key path / schema type pairs to this schema. */
242
242
  add(obj: SchemaDefinition<SchemaDefinitionType<EnforcedDocType>> | Schema, prefix?: string): this;
@@ -293,14 +293,14 @@ declare module 'mongoose' {
293
293
  loadClass(model: Function, onlyVirtuals?: boolean): this;
294
294
 
295
295
  /** Adds an instance method to documents constructed from Models compiled from this schema. */
296
- method<Context = any>(name: string, fn: (this: Context, ...args: any[]) => any, opts?: any): this;
296
+ method<Context = THydratedDocumentType>(name: string, fn: (this: Context, ...args: any[]) => any, opts?: any): this;
297
297
  method(obj: Partial<TInstanceMethods>): this;
298
298
 
299
299
  /** Object of currently defined methods on this schema. */
300
300
  methods: { [F in keyof TInstanceMethods]: TInstanceMethods[F] } & AnyObject;
301
301
 
302
302
  /** The original object passed to the schema constructor */
303
- obj: SchemaDefinition<SchemaDefinitionType<EnforcedDocType>>;
303
+ obj: SchemaDefinition<SchemaDefinitionType<EnforcedDocType>, EnforcedDocType>;
304
304
 
305
305
  /** Gets/sets schema paths. */
306
306
  path<ResultType extends SchemaType = SchemaType<any, THydratedDocumentType>>(path: string): ResultType;
@@ -484,26 +484,26 @@ declare module 'mongoose' {
484
484
  ? DateSchemaDefinition
485
485
  : (Function | string);
486
486
 
487
- export type SchemaDefinitionProperty<T = undefined> = SchemaDefinitionWithBuiltInClass<T> |
488
- SchemaTypeOptions<T extends undefined ? any : T> |
487
+ export type SchemaDefinitionProperty<T = undefined, EnforcedDocType = any> = SchemaDefinitionWithBuiltInClass<T> |
488
+ SchemaTypeOptions<T extends undefined ? any : T, EnforcedDocType> |
489
489
  typeof SchemaType |
490
490
  Schema<any, any, any> |
491
491
  Schema<any, any, any>[] |
492
- SchemaTypeOptions<T extends undefined ? any : Unpacked<T>>[] |
492
+ SchemaTypeOptions<T extends undefined ? any : Unpacked<T>, EnforcedDocType>[] |
493
493
  Function[] |
494
- SchemaDefinition<T> |
495
- SchemaDefinition<Unpacked<T>>[] |
494
+ SchemaDefinition<T, EnforcedDocType> |
495
+ SchemaDefinition<Unpacked<T>, EnforcedDocType>[] |
496
496
  typeof Schema.Types.Mixed |
497
- MixedSchemaTypeOptions;
497
+ MixedSchemaTypeOptions<EnforcedDocType>;
498
498
 
499
- export type SchemaDefinition<T = undefined> = T extends undefined
499
+ export type SchemaDefinition<T = undefined, EnforcedDocType = any> = T extends undefined
500
500
  ? { [path: string]: SchemaDefinitionProperty; }
501
- : { [path in keyof T]?: SchemaDefinitionProperty<T[path]>; };
501
+ : { [path in keyof T]?: SchemaDefinitionProperty<T[path], EnforcedDocType>; };
502
502
 
503
503
  export type AnyArray<T> = T[] | ReadonlyArray<T>;
504
504
  export type ExtractMongooseArray<T> = T extends Types.Array<any> ? AnyArray<Unpacked<T>> : T;
505
505
 
506
- export interface MixedSchemaTypeOptions extends SchemaTypeOptions<Schema.Types.Mixed> {
506
+ export interface MixedSchemaTypeOptions<EnforcedDocType> extends SchemaTypeOptions<Schema.Types.Mixed, EnforcedDocType> {
507
507
  type: typeof Schema.Types.Mixed;
508
508
  }
509
509
 
package/types/models.d.ts CHANGED
@@ -473,13 +473,6 @@ declare module 'mongoose' {
473
473
  TRawDocType,
474
474
  'findOne'
475
475
  >;
476
- exists(filter: FilterQuery<TRawDocType>): QueryWithHelpers<
477
- { _id: InferId<TRawDocType> } | null,
478
- THydratedDocumentType,
479
- TQueryHelpers,
480
- TRawDocType,
481
- 'findOne'
482
- >;
483
476
 
484
477
  /** Creates a `find` query: gets a list of documents that match `filter`. */
485
478
  find<ResultDoc = THydratedDocumentType>(
@@ -39,7 +39,7 @@ declare module 'mongoose' {
39
39
 
40
40
  type DefaultType<T> = T extends Schema.Types.Mixed ? any : Partial<ExtractMongooseArray<T>>;
41
41
 
42
- class SchemaTypeOptions<T> {
42
+ class SchemaTypeOptions<T, EnforcedDocType = any> {
43
43
  type?:
44
44
  T extends string ? StringSchemaDefinition :
45
45
  T extends number ? NumberSchemaDefinition :
@@ -48,12 +48,12 @@ declare module 'mongoose' {
48
48
  T extends Map<any, any> ? SchemaDefinition<typeof Map> :
49
49
  T extends Buffer ? SchemaDefinition<typeof Buffer> :
50
50
  T extends Types.ObjectId ? ObjectIdSchemaDefinition :
51
- T extends Types.ObjectId[] ? AnyArray<ObjectIdSchemaDefinition> | AnyArray<SchemaTypeOptions<ObjectId>> :
52
- T extends object[] ? (AnyArray<Schema<any, any, any>> | AnyArray<SchemaDefinition<Unpacked<T>>> | AnyArray<SchemaTypeOptions<Unpacked<T>>>) :
53
- T extends string[] ? AnyArray<StringSchemaDefinition> | AnyArray<SchemaTypeOptions<string>> :
54
- T extends number[] ? AnyArray<NumberSchemaDefinition> | AnyArray<SchemaTypeOptions<number>> :
55
- T extends boolean[] ? AnyArray<BooleanSchemaDefinition> | AnyArray<SchemaTypeOptions<boolean>> :
56
- T extends Function[] ? AnyArray<Function | string> | AnyArray<SchemaTypeOptions<Unpacked<T>>> :
51
+ T extends Types.ObjectId[] ? AnyArray<ObjectIdSchemaDefinition> | AnyArray<SchemaTypeOptions<ObjectId, EnforcedDocType>> :
52
+ T extends object[] ? (AnyArray<Schema<any, any, any>> | AnyArray<SchemaDefinition<Unpacked<T>>> | AnyArray<SchemaTypeOptions<Unpacked<T>, EnforcedDocType>>) :
53
+ T extends string[] ? AnyArray<StringSchemaDefinition> | AnyArray<SchemaTypeOptions<string, EnforcedDocType>> :
54
+ T extends number[] ? AnyArray<NumberSchemaDefinition> | AnyArray<SchemaTypeOptions<number, EnforcedDocType>> :
55
+ T extends boolean[] ? AnyArray<BooleanSchemaDefinition> | AnyArray<SchemaTypeOptions<boolean, EnforcedDocType>> :
56
+ T extends Function[] ? AnyArray<Function | string> | AnyArray<SchemaTypeOptions<Unpacked<T>, EnforcedDocType>> :
57
57
  T | typeof SchemaType | Schema<any, any, any> | SchemaDefinition<T> | Function | AnyArray<Function>;
58
58
 
59
59
  /** Defines a virtual with the given name that gets/sets this path. */
@@ -74,13 +74,13 @@ declare module 'mongoose' {
74
74
  * path cannot be set to a nullish value. If a function, Mongoose calls the
75
75
  * function and only checks for nullish values if the function returns a truthy value.
76
76
  */
77
- required?: boolean | (() => boolean) | [boolean, string] | [() => boolean, string];
77
+ required?: boolean | ((this: EnforcedDocType) => boolean) | [boolean, string] | [(this: EnforcedDocType) => boolean, string];
78
78
 
79
79
  /**
80
80
  * The default value for this path. If a function, Mongoose executes the function
81
81
  * and uses the return value as the default.
82
82
  */
83
- default?: DefaultType<T> | ((this: any, doc: any) => DefaultType<T>) | null;
83
+ default?: DefaultType<T> | ((this: EnforcedDocType, doc: any) => DefaultType<T>) | null;
84
84
 
85
85
  /**
86
86
  * The model that `populate()` should use if populating this path.