mongoose 8.7.3 → 8.8.1

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.
@@ -11,9 +11,12 @@ const SchemaArrayOptions = require('../options/schemaArrayOptions');
11
11
  const SchemaType = require('../schemaType');
12
12
  const CastError = SchemaType.CastError;
13
13
  const Mixed = require('./mixed');
14
+ const VirtualOptions = require('../options/virtualOptions');
15
+ const VirtualType = require('../virtualType');
14
16
  const arrayDepth = require('../helpers/arrayDepth');
15
17
  const cast = require('../cast');
16
18
  const clone = require('../helpers/clone');
19
+ const getConstructorName = require('../helpers/getConstructorName');
17
20
  const isOperator = require('../helpers/query/isOperator');
18
21
  const util = require('util');
19
22
  const utils = require('../utils');
@@ -217,6 +220,12 @@ SchemaArray._checkRequired = SchemaType.prototype.checkRequired;
217
220
 
218
221
  SchemaArray.checkRequired = SchemaType.checkRequired;
219
222
 
223
+ /*!
224
+ * Virtuals defined on this array itself.
225
+ */
226
+
227
+ SchemaArray.prototype.virtuals = null;
228
+
220
229
  /**
221
230
  * Check if the given value satisfies the `required` validator.
222
231
  *
@@ -575,6 +584,32 @@ SchemaArray.prototype.castForQuery = function($conditional, val, context) {
575
584
  }
576
585
  };
577
586
 
587
+ /**
588
+ * Add a virtual to this array. Specifically to this array, not the individual elements.
589
+ *
590
+ * @param {String} name
591
+ * @param {Object} [options]
592
+ * @api private
593
+ */
594
+
595
+ SchemaArray.prototype.virtual = function virtual(name, options) {
596
+ if (name instanceof VirtualType || getConstructorName(name) === 'VirtualType') {
597
+ return this.virtual(name.path, name.options);
598
+ }
599
+ options = new VirtualOptions(options);
600
+
601
+ if (utils.hasUserDefinedProperty(options, ['ref', 'refPath'])) {
602
+ throw new MongooseError('Cannot set populate virtual as a property of an array');
603
+ }
604
+
605
+ const virtual = new VirtualType(options, name);
606
+ if (this.virtuals === null) {
607
+ this.virtuals = {};
608
+ }
609
+ this.virtuals[name] = virtual;
610
+ return virtual;
611
+ };
612
+
578
613
  function cast$all(val, context) {
579
614
  if (!Array.isArray(val)) {
580
615
  val = [val];
@@ -429,7 +429,7 @@ SchemaDocumentArray.prototype.cast = function(value, doc, init, prev, options) {
429
429
  // We need to create a new array, otherwise change tracking will
430
430
  // update the old doc (gh-4449)
431
431
  if (!options.skipDocumentArrayCast || utils.isMongooseDocumentArray(value)) {
432
- value = new MongooseDocumentArray(value, path, doc);
432
+ value = new MongooseDocumentArray(value, path, doc, this);
433
433
  }
434
434
 
435
435
  if (prev != null) {
package/lib/schema.js CHANGED
@@ -2304,6 +2304,7 @@ Schema.prototype.indexes = function() {
2304
2304
  * @param {Boolean} [options.count=false] Only works with populate virtuals. If [truthy](https://masteringjs.io/tutorials/fundamentals/truthy), this populate virtual will contain the number of documents rather than the documents themselves when you `populate()`.
2305
2305
  * @param {Function|null} [options.get=null] Adds a [getter](https://mongoosejs.com/docs/tutorials/getters-setters.html) to this virtual to transform the populated doc.
2306
2306
  * @param {Object|Function} [options.match=null] Apply a default [`match` option to populate](https://mongoosejs.com/docs/populate.html#match), adding an additional filter to the populate query.
2307
+ * @param {Boolean} [options.applyToArray=false] If true and the given `name` is a direct child of an array, apply the virtual to the array rather than the elements.
2307
2308
  * @return {VirtualType}
2308
2309
  */
2309
2310
 
@@ -2416,6 +2417,15 @@ Schema.prototype.virtual = function(name, options) {
2416
2417
  return mem[part];
2417
2418
  }, this.tree);
2418
2419
 
2420
+ if (options && options.applyToArray && parts.length > 1) {
2421
+ const path = this.path(parts.slice(0, -1).join('.'));
2422
+ if (path && path.$isMongooseArray) {
2423
+ return path.virtual(parts[parts.length - 1], options);
2424
+ } else {
2425
+ throw new MongooseError(`Path "${path}" is not an array`);
2426
+ }
2427
+ }
2428
+
2419
2429
  return virtuals[name];
2420
2430
  };
2421
2431
 
@@ -90,6 +90,9 @@ function MongooseArray(values, path, doc, schematype) {
90
90
  if (mongooseArrayMethods.hasOwnProperty(prop)) {
91
91
  return mongooseArrayMethods[prop];
92
92
  }
93
+ if (schematype && schematype.virtuals && schematype.virtuals.hasOwnProperty(prop)) {
94
+ return schematype.virtuals[prop].applyGetters(undefined, target);
95
+ }
93
96
  if (typeof prop === 'string' && numberRE.test(prop) && schematype?.$embeddedSchemaType != null) {
94
97
  return schematype.$embeddedSchemaType.applyGetters(__array[prop], doc);
95
98
  }
@@ -101,6 +104,8 @@ function MongooseArray(values, path, doc, schematype) {
101
104
  mongooseArrayMethods.set.call(proxy, prop, value, false);
102
105
  } else if (internals.hasOwnProperty(prop)) {
103
106
  internals[prop] = value;
107
+ } else if (schematype && schematype.virtuals && schematype.virtuals.hasOwnProperty(prop)) {
108
+ schematype.virtuals[prop].applySetters(value, target);
104
109
  } else {
105
110
  __array[prop] = value;
106
111
  }
@@ -28,7 +28,7 @@ const numberRE = /^\d+$/;
28
28
  * @see https://bit.ly/f6CnZU
29
29
  */
30
30
 
31
- function MongooseDocumentArray(values, path, doc) {
31
+ function MongooseDocumentArray(values, path, doc, schematype) {
32
32
  const __array = [];
33
33
 
34
34
  const internals = {
@@ -84,6 +84,9 @@ function MongooseDocumentArray(values, path, doc) {
84
84
  if (DocumentArrayMethods.hasOwnProperty(prop)) {
85
85
  return DocumentArrayMethods[prop];
86
86
  }
87
+ if (schematype && schematype.virtuals && schematype.virtuals.hasOwnProperty(prop)) {
88
+ return schematype.virtuals[prop].applyGetters(undefined, target);
89
+ }
87
90
  if (ArrayMethods.hasOwnProperty(prop)) {
88
91
  return ArrayMethods[prop];
89
92
  }
@@ -95,6 +98,8 @@ function MongooseDocumentArray(values, path, doc) {
95
98
  DocumentArrayMethods.set.call(proxy, prop, value, false);
96
99
  } else if (internals.hasOwnProperty(prop)) {
97
100
  internals[prop] = value;
101
+ } else if (schematype && schematype.virtuals && schematype.virtuals.hasOwnProperty(prop)) {
102
+ schematype.virtuals[prop].applySetters(value, target);
98
103
  } else {
99
104
  __array[prop] = value;
100
105
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "8.7.3",
4
+ "version": "8.8.1",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -21,15 +21,15 @@
21
21
  "dependencies": {
22
22
  "bson": "^6.7.0",
23
23
  "kareem": "2.6.3",
24
- "mongodb": "6.9.0",
24
+ "mongodb": "~6.10.0",
25
25
  "mpath": "0.9.0",
26
26
  "mquery": "5.0.0",
27
27
  "ms": "2.1.3",
28
28
  "sift": "17.1.3"
29
29
  },
30
30
  "devDependencies": {
31
- "@babel/core": "7.24.7",
32
- "@babel/preset-env": "7.25.4",
31
+ "@babel/core": "7.26.0",
32
+ "@babel/preset-env": "7.26.0",
33
33
  "@typescript-eslint/eslint-plugin": "^8.4.0",
34
34
  "@typescript-eslint/parser": "^8.4.0",
35
35
  "acquit": "1.3.0",
@@ -41,7 +41,7 @@
41
41
  "broken-link-checker": "^0.7.8",
42
42
  "buffer": "^5.6.0",
43
43
  "cheerio": "1.0.0",
44
- "crypto-browserify": "3.12.0",
44
+ "crypto-browserify": "3.12.1",
45
45
  "dotenv": "16.4.5",
46
46
  "dox": "1.0.0",
47
47
  "eslint": "8.57.0",
@@ -53,11 +53,11 @@
53
53
  "lodash.isequal": "4.5.0",
54
54
  "lodash.isequalwith": "4.4.0",
55
55
  "markdownlint-cli2": "^0.14.0",
56
- "marked": "14.1.2",
56
+ "marked": "14.1.3",
57
57
  "mkdirp": "^3.0.1",
58
- "mocha": "10.7.3",
58
+ "mocha": "10.8.2",
59
59
  "moment": "2.30.1",
60
- "mongodb-memory-server": "10.0.1",
60
+ "mongodb-memory-server": "10.1.2",
61
61
  "ncp": "^2.0.0",
62
62
  "nyc": "15.1.0",
63
63
  "pug": "3.0.3",
@@ -65,9 +65,9 @@
65
65
  "sinon": "19.0.2",
66
66
  "stream-browserify": "3.0.0",
67
67
  "tsd": "0.31.2",
68
- "typescript": "5.6.2",
69
- "uuid": "10.0.0",
70
- "webpack": "5.95.0"
68
+ "typescript": "5.6.3",
69
+ "uuid": "11.0.2",
70
+ "webpack": "5.96.1"
71
71
  },
72
72
  "directories": {
73
73
  "lib": "./lib/mongoose"
@@ -256,10 +256,17 @@ declare module 'mongoose' {
256
256
  set(value: string | Record<string, any>): this;
257
257
 
258
258
  /** The return value of this method is used in calls to JSON.stringify(doc). */
259
- toJSON(options?: ToObjectOptions & { flattenMaps?: true }): FlattenMaps<Require_id<DocType>>;
259
+ toJSON(options?: ToObjectOptions & { flattenMaps?: true, flattenObjectIds?: false }): FlattenMaps<Require_id<DocType>>;
260
+ toJSON(options: ToObjectOptions & { flattenObjectIds: false }): FlattenMaps<Require_id<DocType>>;
261
+ toJSON(options: ToObjectOptions & { flattenObjectIds: true }): ObjectIdToString<FlattenMaps<Require_id<DocType>>>;
260
262
  toJSON(options: ToObjectOptions & { flattenMaps: false }): Require_id<DocType>;
261
- toJSON<T = Require_id<DocType>>(options?: ToObjectOptions & { flattenMaps?: true }): FlattenMaps<T>;
263
+ toJSON(options: ToObjectOptions & { flattenMaps: false; flattenObjectIds: true }): ObjectIdToString<Require_id<DocType>>;
264
+
265
+ toJSON<T = Require_id<DocType>>(options?: ToObjectOptions & { flattenMaps?: true, flattenObjectIds?: false }): FlattenMaps<T>;
266
+ toJSON<T = Require_id<DocType>>(options: ToObjectOptions & { flattenObjectIds: false }): FlattenMaps<T>;
267
+ toJSON<T = Require_id<DocType>>(options: ToObjectOptions & { flattenObjectIds: true }): ObjectIdToString<FlattenMaps<T>>;
262
268
  toJSON<T = Require_id<DocType>>(options: ToObjectOptions & { flattenMaps: false }): T;
269
+ toJSON<T = Require_id<DocType>>(options: ToObjectOptions & { flattenMaps: false; flattenObjectIds: true }): ObjectIdToString<T>;
263
270
 
264
271
  /** Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)). */
265
272
  toObject(options?: ToObjectOptions): Require_id<DocType>;
package/types/index.d.ts CHANGED
@@ -25,7 +25,7 @@
25
25
  /// <reference path="./virtuals.d.ts" />
26
26
  /// <reference path="./augmentations.d.ts" />
27
27
 
28
- declare class NativeDate extends global.Date { }
28
+ declare class NativeDate extends globalThis.Date { }
29
29
 
30
30
  declare module 'mongoose' {
31
31
  import Kareem = require('kareem');
@@ -140,7 +140,7 @@ declare module 'mongoose' {
140
140
 
141
141
  export type Default__v<T> = T extends { __v?: infer U }
142
142
  ? T
143
- : T & { __v?: number };
143
+ : T & { __v: number };
144
144
 
145
145
  /** Helper type for getting the hydrated document type from the raw document type. The hydrated document type is what `new MyModel()` returns. */
146
146
  export type HydratedDocument<
@@ -623,6 +623,9 @@ declare module 'mongoose' {
623
623
  /** Additional options like `limit` and `lean`. */
624
624
  options?: QueryOptions<DocType> & { match?: AnyObject };
625
625
 
626
+ /** If true and the given `name` is a direct child of an array, apply the virtual to the array rather than the elements. */
627
+ applyToArray?: boolean;
628
+
626
629
  /** Additional options for plugins */
627
630
  [extra: string]: any;
628
631
  }
@@ -57,7 +57,8 @@ declare module 'mongoose' {
57
57
  type IndexDefinition = Record<string, IndexDirection>;
58
58
 
59
59
  interface SyncIndexesOptions extends mongodb.CreateIndexesOptions {
60
- continueOnError?: boolean
60
+ continueOnError?: boolean;
61
+ hideIndexes?: boolean;
61
62
  }
62
63
  type ConnectionSyncIndexesResult = Record<string, OneCollectionSyncIndexesResult>;
63
64
  type OneCollectionSyncIndexesResult = Array<string> & mongodb.MongoServerError;
package/types/models.d.ts CHANGED
@@ -126,7 +126,7 @@ declare module 'mongoose' {
126
126
  }
127
127
 
128
128
  interface ModifyResult<T> {
129
- value: Require_id<T> | null;
129
+ value: Default__v<Require_id<T>> | null;
130
130
  /** see https://www.mongodb.com/docs/manual/reference/command/findAndModify/#lasterrorobject */
131
131
  lastErrorObject?: {
132
132
  updatedExisting?: boolean;
@@ -292,6 +292,11 @@ declare module 'mongoose' {
292
292
  /* Apply virtuals to the given POJO. */
293
293
  applyVirtuals(obj: AnyObject, virtalsToApply?: string[]): AnyObject;
294
294
 
295
+ /**
296
+ * Apply this model's timestamps to a given POJO, including subdocument timestamps
297
+ */
298
+ applyTimestamps(obj: AnyObject, options?: { isUpdate?: boolean, currentTime?: () => Date }): AnyObject;
299
+
295
300
  /**
296
301
  * Sends multiple `insertOne`, `updateOne`, `updateMany`, `replaceOne`,
297
302
  * `deleteOne`, and/or `deleteMany` operations to the MongoDB server in one
package/types/query.d.ts CHANGED
@@ -20,10 +20,12 @@ declare module 'mongoose' {
20
20
  | 'context'
21
21
  | 'multipleCastError'
22
22
  | 'overwriteDiscriminatorKey'
23
+ | 'overwriteImmutable'
23
24
  | 'populate'
24
25
  | 'runValidators'
25
26
  | 'sanitizeProjection'
26
27
  | 'sanitizeFilter'
28
+ | 'schemaLevelProjections'
27
29
  | 'setDefaultsOnInsert'
28
30
  | 'strict'
29
31
  | 'strictQuery'
@@ -153,6 +155,11 @@ declare module 'mongoose' {
153
155
  new?: boolean;
154
156
 
155
157
  overwriteDiscriminatorKey?: boolean;
158
+ /**
159
+ * Mongoose removes updated immutable properties from `update` by default (excluding $setOnInsert).
160
+ * Set `overwriteImmutable` to `true` to allow updating immutable properties using other update operators.
161
+ */
162
+ overwriteImmutable?: boolean;
156
163
  projection?: ProjectionType<DocType>;
157
164
  /**
158
165
  * if true, returns the full ModifyResult rather than just the document
@@ -179,6 +186,11 @@ declare module 'mongoose' {
179
186
  * aren't explicitly allowed using `mongoose.trusted()`.
180
187
  */
181
188
  sanitizeFilter?: boolean;
189
+ /**
190
+ * Enable or disable schema level projections for this query. Enabled by default.
191
+ * Set to `false` to include fields with `select: false` in the query result by default.
192
+ */
193
+ schemaLevelProjections?: boolean;
182
194
  setDefaultsOnInsert?: boolean;
183
195
  skip?: number;
184
196
  sort?: any;
@@ -211,7 +223,7 @@ declare module 'mongoose' {
211
223
  type QueryOpThatReturnsDocument = 'find' | 'findOne' | 'findOneAndUpdate' | 'findOneAndReplace' | 'findOneAndDelete';
212
224
 
213
225
  type GetLeanResultType<RawDocType, ResultType, QueryOp> = QueryOp extends QueryOpThatReturnsDocument
214
- ? (ResultType extends any[] ? Require_id<BufferToBinary<FlattenMaps<RawDocType>>>[] : Require_id<BufferToBinary<FlattenMaps<RawDocType>>>)
226
+ ? (ResultType extends any[] ? Default__v<Require_id<BufferToBinary<FlattenMaps<RawDocType>>>>[] : Default__v<Require_id<BufferToBinary<FlattenMaps<RawDocType>>>>)
215
227
  : ResultType;
216
228
 
217
229
  type MergePopulatePaths<RawDocType, ResultType, QueryOp, Paths, TQueryHelpers, TInstanceMethods = Record<string, never>> = QueryOp extends QueryOpThatReturnsDocument
@@ -734,6 +746,12 @@ declare module 'mongoose' {
734
746
  */
735
747
  sanitizeProjection(value: boolean): this;
736
748
 
749
+ /**
750
+ * Enable or disable schema level projections for this query. Enabled by default.
751
+ * Set to `false` to include fields with `select: false` in the query result by default.
752
+ */
753
+ schemaLevelProjections(value: boolean): this;
754
+
737
755
  /** Specifies which document fields to include or exclude (also known as the query "projection") */
738
756
  select<RawDocTypeOverride extends { [P in keyof RawDocType]?: any } = {}>(
739
757
  arg: string | string[] | Record<string, number | boolean | string | object>