mongoose 9.7.4 → 9.8.0

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/README.md CHANGED
@@ -32,7 +32,7 @@ Check out the [plugins search site](https://plugins.mongoosejs.io/) to see hundr
32
32
  Pull requests are always welcome! Please base pull requests against the `master`
33
33
  branch and follow the [contributing guide](https://github.com/Automattic/mongoose/blob/master/CONTRIBUTING.md).
34
34
 
35
- If your pull requests makes documentation changes, please do **not**
35
+ If your pull request makes documentation changes, please do **not**
36
36
  modify any `.html` files. The `.html` files are compiled code, so please make
37
37
  your changes in `docs/*.pug`, `lib/*.js`, or `test/docs/*.js`.
38
38
 
@@ -341,7 +341,7 @@ new Schema({
341
341
  ### Driver Access
342
342
 
343
343
  Mongoose is built on top of the [official MongoDB Node.js driver](https://github.com/mongodb/node-mongodb-native). Each mongoose model keeps a reference to a [native MongoDB driver collection](http://mongodb.github.io/node-mongodb-native/2.1/api/Collection.html). The collection object can be accessed using `YourModel.collection`. However, using the collection object directly bypasses all mongoose features, including hooks, validation, etc. The one
344
- notable exception that `YourModel.collection` still buffers
344
+ notable exception is that `YourModel.collection` still buffers
345
345
  commands. As such, `YourModel.collection.find()` will **not**
346
346
  return a cursor.
347
347
 
package/lib/aggregate.js CHANGED
@@ -615,6 +615,9 @@ Aggregate.prototype.graphLookup = function(options) {
615
615
  *
616
616
  * aggregate.sample(3); // Add a pipeline that picks 3 random documents
617
617
  *
618
+ * // `$match` before `$sample` samples from the filtered subset
619
+ * aggregate.match({ difficulty: 'easy' }).sample(3);
620
+ *
618
621
  * @see $sample https://www.mongodb.com/docs/manual/reference/operator/aggregation/sample/#pipe._S_sample
619
622
  * @param {number} size number of random documents to pick
620
623
  * @return {Aggregate}
package/lib/cast.js CHANGED
@@ -413,7 +413,7 @@ function _cast(val, numbertype, context) {
413
413
  _cast(item, numbertype, context);
414
414
  val[nkey] = item;
415
415
  } else {
416
- val[nkey] = numbertype.castForQuery({ val: item, context: context });
416
+ val[nkey] = numbertype.castForQuery(null, item, context);
417
417
  }
418
418
  }
419
419
  }
package/lib/document.js CHANGED
@@ -756,6 +756,7 @@ function init(self, obj, doc, opts, prefix) {
756
756
  let i;
757
757
  const strict = self.$__.strictMode;
758
758
  const docSchema = self.$__schema;
759
+ const strictRead = docSchema.options.strictRead;
759
760
 
760
761
  for (let index = 0; index < len; ++index) {
761
762
  i = keys[index];
@@ -773,6 +774,14 @@ function init(self, obj, doc, opts, prefix) {
773
774
  }
774
775
 
775
776
  const value = obj[i];
777
+ if (!schemaType && strictRead && docSchema.pathType(path) === 'adhocOrUndefined') {
778
+ if (strictRead === 'throw') {
779
+ throw new StrictModeError(path, 'Field `' + path + '` is not in schema and strictRead is set to throw.');
780
+ } else if (strictRead === true) {
781
+ continue;
782
+ }
783
+ }
784
+
776
785
  if (!schemaType && utils.isPOJO(value)) {
777
786
  // assume nested object
778
787
  if (!doc[i]) {
@@ -785,6 +794,13 @@ function init(self, obj, doc, opts, prefix) {
785
794
  }
786
795
  init(self, value, doc[i], opts, path + '.');
787
796
  } else if (!schemaType) {
797
+ // Handle strictRead: filter unknown fields during document hydration from DB
798
+ if (strictRead === 'throw') {
799
+ throw new StrictModeError(path, 'Field `' + path + '` is not in schema and strictRead is set to throw.');
800
+ } else if (strictRead === true) {
801
+ // Skip this field - do not store in _doc
802
+ continue;
803
+ }
788
804
  doc[i] = value;
789
805
  if (!strict && !prefix) {
790
806
  self[i] = value;
@@ -3567,6 +3583,10 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
3567
3583
  * @param {number} [options.wtimeout] sets a [timeout for the write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](https://mongoosejs.com/docs/guide.html#writeConcern).
3568
3584
  * @param {boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://www.mongodb.com/docs/manual/reference/limits/#Restrictions-on-Field-Names)
3569
3585
  * @param {boolean} [options.timestamps=true] if `false` and [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this `save()`.
3586
+ * @param {Array} [options.pathsToSave] An array of paths that tell mongoose to only validate and save the paths in `pathsToSave`.
3587
+ * @param {boolean|object} [options.middleware=true] set to `false` to skip all user-defined middleware
3588
+ * @param {boolean} [options.middleware.pre=true] set to `false` to skip only pre hooks
3589
+ * @param {boolean} [options.middleware.post=true] set to `false` to skip only post hooks
3570
3590
  * @method save
3571
3591
  * @memberOf Document
3572
3592
  * @instance
@@ -4718,6 +4738,9 @@ Document.prototype.equals = function(doc) {
4718
4738
  * @param {boolean} [options.getters=false] if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](https://mongoosejs.com/docs/schematypes.html#schematype-options).
4719
4739
  * @param {boolean} [options.clone=false] When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
4720
4740
  * @param {object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
4741
+ * @param {boolean} [options.skipInvalidIds=false] By default, Mongoose throws a cast error if `localField` and `foreignField` schemas don't line up. If you enable this option, Mongoose will instead filter out any `localField` properties that cannot be casted to `foreignField`'s schema type.
4742
+ * @param {number} [options.perDocumentLimit=null] For legacy reasons, `limit` with `populate()` may give incorrect results when populating multiple parent documents because it executes a single query for all parents. If you set `perDocumentLimit`, Mongoose will execute a separate query per parent document to ensure correct per-document `limit`.
4743
+ * @param {boolean} [options.strictPopulate=true] Set to false to allow populating paths that aren't defined in the given model's schema.
4721
4744
  * @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
4722
4745
  * @param {object} [options.options=null] Additional options like `limit` and `lean`.
4723
4746
  * @param {boolean} [options.forceRepopulate=true] Set to `false` to prevent Mongoose from repopulating paths that are already populated
@@ -5147,8 +5170,8 @@ Document.prototype.$__delta = function $__delta(pathsToSave, pathsToSaveSet) {
5147
5170
  const optimisticConcurrencyExcludeSet = this.$__schema.options._optimisticConcurrencyExcludeSet;
5148
5171
  const modPaths = this.directModifiedPaths();
5149
5172
  const hasRelevantModPaths = pathsToSave == null ?
5150
- modPaths.find(path => !_pathOverlapsSet(path, optimisticConcurrencyExcludeSet)) :
5151
- modPaths.find(path => !_pathOverlapsSet(path, optimisticConcurrencyExcludeSet) && isInPathsToSave(path, pathsToSaveSet, pathsToSave));
5173
+ modPaths.find(path => !_pathOrAncestorInSet(path, optimisticConcurrencyExcludeSet)) :
5174
+ modPaths.find(path => !_pathOrAncestorInSet(path, optimisticConcurrencyExcludeSet) && isInPathsToSave(path, pathsToSaveSet, pathsToSave));
5152
5175
  if (hasRelevantModPaths) {
5153
5176
  this.$__.version = dirty.length ? VERSION_ALL : VERSION_WHERE;
5154
5177
  }
@@ -5661,34 +5684,17 @@ Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
5661
5684
  }
5662
5685
  };
5663
5686
 
5664
- /*!
5665
- * Increment this document's version if necessary.
5666
- */
5667
-
5668
- Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
5669
- if (!this.$__.version) return;
5670
- const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
5671
-
5672
- this.$__.version = undefined;
5673
- if (doIncrement) {
5674
- const key = this.$__schema.options.versionKey;
5675
- const version = this.$__getValue(key) || 0;
5676
- this.$__setValue(key, version + 1); // increment version if was successful
5677
- }
5678
- };
5679
-
5680
5687
  /*!
5681
5688
  * Module exports.
5682
5689
  */
5683
5690
 
5684
5691
  /*!
5685
- * Check if `path`, any of its ancestor paths, or any of its descendant paths
5686
- * exist in `pathSet`.
5692
+ * Check if `path` or any of its ancestor paths exist in `pathSet`.
5687
5693
  * For example:
5688
- * _pathOverlapsSet('profile.firstName', Set(['profile'])) === true
5689
- * _pathOverlapsSet('profile', Set(['profile.firstName'])) === true
5694
+ * _pathOrAncestorInSet('profile.firstName', Set(['profile'])) === true
5695
+ * _pathOrAncestorInSet('profile', Set(['profile.firstName'])) === false
5690
5696
  */
5691
- function _pathOverlapsSet(path, pathSet) {
5697
+ function _pathOrAncestorInSet(path, pathSet) {
5692
5698
  if (pathSet.has(path)) {
5693
5699
  return true;
5694
5700
  }
@@ -5699,6 +5705,20 @@ function _pathOverlapsSet(path, pathSet) {
5699
5705
  }
5700
5706
  idx = path.indexOf('.', idx + 1);
5701
5707
  }
5708
+ return false;
5709
+ }
5710
+
5711
+ /*!
5712
+ * Check if `path`, any of its ancestor paths, or any of its descendant paths
5713
+ * exist in `pathSet`.
5714
+ * For example:
5715
+ * _pathOverlapsSet('profile.firstName', Set(['profile'])) === true
5716
+ * _pathOverlapsSet('profile', Set(['profile.firstName'])) === true
5717
+ */
5718
+ function _pathOverlapsSet(path, pathSet) {
5719
+ if (_pathOrAncestorInSet(path, pathSet)) {
5720
+ return true;
5721
+ }
5702
5722
  for (const p of pathSet) {
5703
5723
  if (p.length > path.length + 1 && p[path.length] === '.' && p.slice(0, path.length) === path) {
5704
5724
  return true;
package/lib/model.js CHANGED
@@ -3656,12 +3656,16 @@ async function buildPreSavePromise(document, options) {
3656
3656
  }
3657
3657
 
3658
3658
  async function handleSuccessfulWrite(document, options) {
3659
- if (document.$isNew) {
3659
+ const wasNew = document.$isNew;
3660
+ if (wasNew) {
3660
3661
  _setIsNew(document, false);
3661
3662
  }
3662
3663
 
3663
3664
  document.$__reset();
3664
- document._applyVersionIncrement();
3665
+ // version key gets initialized to 0 when inserting a new document so avoid incrementing version key here
3666
+ if (!wasNew) {
3667
+ document._applyVersionIncrement();
3668
+ }
3665
3669
  const postFilter = buildMiddlewareFilter(options, 'post');
3666
3670
  return document.schema.s.hooks.execPost('save', document, [document], { filter: postFilter });
3667
3671
  }
@@ -3911,6 +3915,12 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
3911
3915
 
3912
3916
  const isANewDocument = document.isNew;
3913
3917
  if (isANewDocument) {
3918
+ // Like `$__version()` on insert, initialize the version key so
3919
+ // inserted documents get the same shape as `save()` gives them
3920
+ const versionKey = document.$__schema.options.versionKey;
3921
+ if (versionKey) {
3922
+ document.$__setValue(versionKey, 0);
3923
+ }
3914
3924
  const writeOperation = { insertOne: { document } };
3915
3925
  utils.injectTimestampsOption(writeOperation.insertOne, options.timestamps);
3916
3926
  return writeOperation;
package/lib/query.js CHANGED
@@ -5088,12 +5088,17 @@ Query.prototype._castUpdate = function _castUpdate(obj) {
5088
5088
  * @param {object} [match] Conditions for the population query
5089
5089
  * @param {object} [options] Options for the population query (sort, etc)
5090
5090
  * @param {string} [options.path=null] The path to populate.
5091
+ * @param {string|PopulateOptions} [options.populate=null] Recursively populate paths in the populated documents. See [deep populate docs](https://mongoosejs.com/docs/populate.html#deep-populate).
5091
5092
  * @param {boolean} [options.retainNullValues=false] by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries.
5092
5093
  * @param {boolean} [options.getters=false] if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. For example, you would need to set this option to `true` if you wanted to [add a `lowercase` getter to your `localField`](https://mongoosejs.com/docs/schematypes.html#schematype-options).
5093
5094
  * @param {boolean} [options.clone=false] When you do `BlogPost.find().populate('author')`, blog posts with the same author will share 1 copy of an `author` doc. Enable this option to make Mongoose clone populated docs before assigning them.
5094
5095
  * @param {object|Function} [options.match=null] Add an additional filter to the populate query. Can be a filter object containing [MongoDB query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/), or a function that returns a filter object.
5096
+ * @param {boolean} [options.skipInvalidIds=false] By default, Mongoose throws a cast error if `localField` and `foreignField` schemas don't line up. If you enable this option, Mongoose will instead filter out any `localField` properties that cannot be casted to `foreignField`'s schema type.
5097
+ * @param {number} [options.perDocumentLimit=null] For legacy reasons, `limit` with `populate()` may give incorrect results because it only executes a single query for every document being populated. If you set `perDocumentLimit`, Mongoose will ensure correct `limit` per document by executing a separate query for each document to `populate()`. For example, `.find().populate({ path: 'test', perDocumentLimit: 2 })` will execute 2 additional queries if `.find()` returns 2 documents.
5098
+ * @param {boolean} [options.strictPopulate=true] Set to false to allow populating paths that aren't defined in the given model's schema.
5095
5099
  * @param {Function} [options.transform=null] Function that Mongoose will call on every populated document that allows you to transform the populated document.
5096
5100
  * @param {object} [options.options=null] Additional options like `limit` and `lean`.
5101
+ * @param {boolean} [options.ordered=false] Set to `true` to execute any populate queries one at a time, as opposed to in parallel. Set this option to `true` if populating multiple paths or paths with multiple models in transactions.
5097
5102
  * @see population https://mongoosejs.com/docs/populate.html
5098
5103
  * @see Query#select https://mongoosejs.com/docs/api/query.html#Query.prototype.select()
5099
5104
  * @see Model.populate https://mongoosejs.com/docs/api/model.html#Model.populate()
@@ -510,9 +510,9 @@ SchemaArray.prototype._castForQuery = function(val, context) {
510
510
  }
511
511
 
512
512
  if (Array.isArray(val)) {
513
- this.setters.reverse().forEach(setter => {
514
- val = setter.call(this, val, this);
515
- });
513
+ for (let i = this.setters.length - 1; i >= 0; i--) {
514
+ val = this.setters[i].call(this, val, this);
515
+ }
516
516
  val = val.map(function(v) {
517
517
  if (utils.isObject(v) && v.$elemMatch) {
518
518
  return v;
package/lib/schema.js CHANGED
@@ -72,6 +72,7 @@ const numberRE = /^\d+$/;
72
72
  * - [shardKey](https://mongoosejs.com/docs/guide.html#shardKey): object - defaults to `null`
73
73
  * - [strict](https://mongoosejs.com/docs/guide.html#strict): bool - defaults to true
74
74
  * - [strictQuery](https://mongoosejs.com/docs/guide.html#strictQuery): bool - defaults to false
75
+ * - [strictRead](https://mongoosejs.com/docs/guide.html#strictRead): bool or 'throw' - defaults to false. If set to `true`, fields not in the schema will be stripped when hydrating documents from MongoDB. If set to `'throw'`, an error will be thrown when a field not in the schema is encountered during document hydration.
75
76
  * - [toJSON](https://mongoosejs.com/docs/guide.html#toJSON) - object - no default
76
77
  * - [toObject](https://mongoosejs.com/docs/guide.html#toObject) - object - no default
77
78
  * - [typeKey](https://mongoosejs.com/docs/guide.html#typeKey) - string - defaults to 'type'
@@ -606,10 +607,12 @@ Schema.prototype.defaultOptions = function(options) {
606
607
  const baseOptions = this.base?.options || {};
607
608
  const defaultStrict = baseOptions.strict ?? true;
608
609
  const defaultStrictQuery = baseOptions.strictQuery ?? false;
610
+ const defaultStrictRead = baseOptions.strictRead ?? false;
609
611
  const defaultId = baseOptions.id ?? true;
610
612
  options = {
611
613
  strict: defaultStrict,
612
614
  strictQuery: defaultStrictQuery,
615
+ strictRead: defaultStrictRead,
613
616
  bufferCommands: true,
614
617
  capped: false, // { size, max, autoIndexId }
615
618
  versionKey: '__v',
@@ -403,7 +403,9 @@ if (util.inspect.custom) {
403
403
 
404
404
  /**
405
405
  * Override `$toObject()` to handle minimizing the whole path. Should not minimize if schematype-level minimize
406
- * is set to false re: gh-11247, gh-14058, gh-14151
406
+ * is set to false re: gh-11247, gh-14058, gh-14151. Should not minimize document array elements: an array
407
+ * element cannot be removed without shifting the array, so minimizing it to `undefined` makes the BSON
408
+ * serializer store `null` re: gh-7322.
407
409
  */
408
410
 
409
411
  Subdocument.prototype.$toObject = function $toObject(options, json) {
@@ -413,7 +415,7 @@ Subdocument.prototype.$toObject = function $toObject(options, json) {
413
415
  // If minimize is set, then we can minimize out the whole object.
414
416
  if (utils.hasOwnKeys(ret) === false && options?._calledWithOptions != null) {
415
417
  const minimize = options._calledWithOptions?.minimize ?? this?.$__schemaTypeOptions?.minimize ?? options.minimize;
416
- if (minimize && !this.constructor.$__required) {
418
+ if (minimize && !this.constructor.$__required && !this.$isDocumentArrayElement) {
417
419
  return undefined;
418
420
  }
419
421
  }
@@ -32,6 +32,7 @@ const VALID_OPTIONS = Object.freeze([
32
32
  'strict',
33
33
  'strictPopulate',
34
34
  'strictQuery',
35
+ 'strictRead',
35
36
  'timestamps.createdAt.immutable',
36
37
  'toJSON',
37
38
  'toObject',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "9.7.4",
4
+ "version": "9.8.0",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "@standard-schema/spec": "^1.1.0",
24
24
  "kareem": "3.3.0",
25
- "mongodb": "~7.2",
25
+ "mongodb": "~7.5",
26
26
  "mpath": "0.9.0",
27
27
  "mquery": "6.0.0",
28
28
  "ms": "2.1.3",
@@ -55,7 +55,7 @@
55
55
  "mkdirp": "^3.0.1",
56
56
  "mocha": "12.0.0-beta-10",
57
57
  "moment": "2.30.1",
58
- "mongodb-client-encryption": "~7.0",
58
+ "mongodb-client-encryption": "^7.2.0",
59
59
  "mongodb-memory-server": "11.2.0",
60
60
  "mongodb-runner": "^6.0.0",
61
61
  "ncp": "^2.0.0",
@@ -99,17 +99,17 @@
99
99
  "mongo": "node ./tools/repl.js",
100
100
  "publish-7x": "npm publish --tag 7x",
101
101
  "create-separate-require-instance": "rm -rf ./node_modules/mongoose-separate-require-instance && node ./scripts/create-tarball && tar -xzf mongoose.tgz -C ./node_modules && mv ./node_modules/package ./node_modules/mongoose-separate-require-instance",
102
- "test": "mocha --exit ./test/*.test.js",
102
+ "test": "mocha --exit --ignore \"test/encryption/**/*.test.js\" \"./test/**/*.test.js\"",
103
103
  "test:ci": "npm run test -- --reporter min",
104
104
  "test-deno": "deno run --allow-env --allow-read --allow-net --allow-run --allow-sys --allow-write ./test/deno.mjs",
105
105
  "test-deno:ci": "npm run test-deno -- --reporter min",
106
- "test-rs": "START_REPLICA_SET=1 mocha --timeout 30000 --exit ./test/*.test.js",
106
+ "test-rs": "START_REPLICA_SET=1 mocha --timeout 30000 --exit --ignore \"test/encryption/**/*.test.js\" \"./test/**/*.test.js\"",
107
107
  "test-rs:ci": "npm run test-rs -- --reporter min",
108
108
  "test:types": "tstyche",
109
109
  "setup-test-encryption": "node scripts/setup-encryption-tests.js",
110
110
  "test-encryption": "mocha --exit ./test/encryption/*.test.js",
111
111
  "test-encryption:ci": "npm run test-encryption -- --reporter min",
112
- "tdd": "mocha --watch --inspect --recursive ./test/*.test.js --watch-files lib/**/*.js test/**/*.js",
112
+ "tdd": "mocha --watch --inspect --ignore \"test/encryption/**/*.test.js\" \"./test/**/*.test.js\" --watch-files lib/**/*.js test/**/*.js",
113
113
  "test-coverage": "c8 --reporter=html --reporter=text npm test",
114
114
  "test-coverage:ci": "c8 --reporter=html --reporter=text npm run test:ci",
115
115
  "ts-benchmark": "cd ./benchmarks/typescript/simple && npm install && npm run benchmark | node ../../../scripts/tsc-diagnostics-check",
package/types/models.d.ts CHANGED
@@ -116,6 +116,8 @@ declare module 'mongoose' {
116
116
  SessionOption {
117
117
  checkKeys?: boolean;
118
118
  j?: boolean;
119
+ /** An array of paths that tell mongoose to only validate and save the paths in `pathsToSave`. */
120
+ pathsToSave?: string[];
119
121
  safe?: boolean | WriteConcern;
120
122
  timestamps?: boolean | QueryTimestampsConfig;
121
123
  validateBeforeSave?: boolean;
@@ -516,8 +518,16 @@ declare module 'mongoose' {
516
518
  /**
517
519
  * Shortcut for creating a new Document from existing raw data, pre-saved in the DB.
518
520
  * The document returned has no paths marked as modified initially.
521
+ * With `strict: false`, fields not in the schema are kept on the document; pass
522
+ * `ExtraFields` to describe their types, e.g.
523
+ * `Model.hydrate<{ totalOrders: number }>(obj, null, { strict: false })`.
519
524
  */
520
- hydrate(obj: any, projection?: ProjectionType<TRawDocType>, options?: HydrateOptions): THydratedDocumentType;
525
+ hydrate<ExtraFields = unknown>(
526
+ obj: any,
527
+ projection: ProjectionType<TRawDocType> | null | undefined,
528
+ options: HydrateOptions & { strict: false }
529
+ ): THydratedDocumentType & ExtraFields;
530
+ hydrate(obj: any, projection?: ProjectionType<TRawDocType> | null | undefined, options?: HydrateOptions): THydratedDocumentType;
521
531
 
522
532
  /**
523
533
  * This function is responsible for building [indexes](https://www.mongodb.com/docs/manual/indexes/),
@@ -192,6 +192,14 @@ declare module 'mongoose' {
192
192
  */
193
193
  strictQuery?: boolean | 'throw';
194
194
 
195
+ /**
196
+ * Sets the default [strictRead](https://mongoosejs.com/docs/guide.html#strictRead) mode for schemas.
197
+ * May be `false`, `true`, or `'throw'`.
198
+ *
199
+ * @default false
200
+ */
201
+ strictRead?: boolean | 'throw';
202
+
195
203
  /**
196
204
  * Overwrites default objects to `toJSON()`, for determining how Mongoose
197
205
  * documents get serialized by `JSON.stringify()`
@@ -61,6 +61,14 @@ declare module 'mongoose' {
61
61
  match?: any;
62
62
  /** optional model to use for population */
63
63
  model?: string | Model<any>;
64
+ /** by default, Mongoose removes null and undefined values from populated arrays. Use this option to make `populate()` retain `null` and `undefined` array entries. */
65
+ retainNullValues?: boolean;
66
+ /** if true, Mongoose will call any getters defined on the `localField`. By default, Mongoose gets the raw value of `localField`. */
67
+ getters?: boolean;
68
+ /** if true, Mongoose will clone populated docs before assigning them, so docs that are populated onto multiple parents don't share 1 copy. */
69
+ clone?: boolean;
70
+ /** By default, Mongoose throws a cast error if `localField` and `foreignField` schemas don't line up. If you enable this option, Mongoose will instead filter out any `localField` properties that cannot be casted to `foreignField`'s schema type. */
71
+ skipInvalidIds?: boolean;
64
72
  /** optional query options like sort, limit, etc */
65
73
  options?: QueryOptions;
66
74
  /** correct limit on populated array */
@@ -158,6 +158,11 @@ declare module 'mongoose' {
158
158
  * [strictQuery](https://mongoosejs.com/docs/guide.html#strictQuery) mode for schemas.
159
159
  */
160
160
  strictQuery?: boolean | 'throw';
161
+ /**
162
+ * May be `false`, `true`, or `'throw'`. Sets the default
163
+ * [strictRead](https://mongoosejs.com/docs/guide.html#strictRead) mode for schemas.
164
+ */
165
+ strictRead?: boolean | 'throw';
161
166
  /** Exactly the same as the toObject option but only applies when the document's toJSON method is called. */
162
167
  toJSON?: ToObjectOptions<DocType, THydratedDocumentType>;
163
168
  /**