mongoose 6.3.0 → 6.3.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.
package/lib/collection.js CHANGED
@@ -23,13 +23,6 @@ function Collection(name, conn, opts) {
23
23
  if (opts === void 0) {
24
24
  opts = {};
25
25
  }
26
- if (opts.capped === void 0) {
27
- opts.capped = {};
28
- }
29
-
30
- if (typeof opts.capped === 'number') {
31
- opts.capped = { size: opts.capped };
32
- }
33
26
 
34
27
  this.opts = opts;
35
28
  this.name = name;
package/lib/document.js CHANGED
@@ -1048,7 +1048,6 @@ Document.prototype.$set = function $set(path, val, type, options) {
1048
1048
  const merge = options.merge;
1049
1049
  const adhoc = type && type !== true;
1050
1050
  const constructing = type === true;
1051
- const typeKey = this.$__schema.options.typeKey;
1052
1051
  let adhocs;
1053
1052
  let keys;
1054
1053
  let i = 0;
@@ -1150,14 +1149,15 @@ Document.prototype.$set = function $set(path, val, type, options) {
1150
1149
  }
1151
1150
  }
1152
1151
 
1153
- // Ensure all properties are in correct order by deleting and recreating every property.
1154
- for (const key of Object.keys(this.$__schema.tree)) {
1155
- if (this._doc.hasOwnProperty(key)) {
1156
- const val = this._doc[key];
1157
- delete this._doc[key];
1158
- this._doc[key] = val;
1159
- }
1152
+ // Ensure all properties are in correct order
1153
+ const orderedDoc = {};
1154
+ const orderedKeys = Object.keys(this.$__schema.tree);
1155
+ for (let i = 0, len = orderedKeys.length; i < len; ++i) {
1156
+ (key = orderedKeys[i]) &&
1157
+ (this._doc.hasOwnProperty(key)) &&
1158
+ (orderedDoc[key] = undefined);
1160
1159
  }
1160
+ this._doc = Object.assign(orderedDoc, this._doc);
1161
1161
 
1162
1162
  return this;
1163
1163
  }
@@ -1381,6 +1381,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1381
1381
  }
1382
1382
 
1383
1383
  let popOpts;
1384
+ const typeKey = this.$__schema.options.typeKey;
1384
1385
  if (schema.options &&
1385
1386
  Array.isArray(schema.options[typeKey]) &&
1386
1387
  schema.options[typeKey].length &&
@@ -1400,7 +1401,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1400
1401
  // later in `$__set()` because we don't take `_doc` when we iterate through
1401
1402
  // a single nested doc. That's to make sure we get the correct context.
1402
1403
  // Otherwise we would double-call the setter, see gh-7196.
1403
- val = schema.applySetters(val, this, false, priorVal);
1404
+ val = schema.applySetters(val, this, false, priorVal, options);
1404
1405
  }
1405
1406
 
1406
1407
  if (Array.isArray(val) &&
package/lib/error/cast.js CHANGED
@@ -23,7 +23,7 @@ class CastError extends MongooseError {
23
23
  const stringValue = getStringValue(value);
24
24
  const valueType = getValueType(value);
25
25
  const messageFormat = getMessageFormat(schemaType);
26
- const msg = formatMessage(null, type, stringValue, path, messageFormat, valueType);
26
+ const msg = formatMessage(null, type, stringValue, path, messageFormat, valueType, reason);
27
27
  super(msg);
28
28
  this.init(type, value, path, reason, schemaType);
29
29
  } else {
@@ -122,7 +122,7 @@ function getMessageFormat(schemaType) {
122
122
  * ignore
123
123
  */
124
124
 
125
- function formatMessage(model, kind, stringValue, path, messageFormat, valueType) {
125
+ function formatMessage(model, kind, stringValue, path, messageFormat, valueType, reason) {
126
126
  if (messageFormat != null) {
127
127
  let ret = messageFormat.
128
128
  replace('{KIND}', kind).
@@ -140,6 +140,11 @@ function formatMessage(model, kind, stringValue, path, messageFormat, valueType)
140
140
  if (model != null) {
141
141
  ret += ' for model "' + model.modelName + '"';
142
142
  }
143
+ if (reason != null &&
144
+ typeof reason.constructor === 'function' &&
145
+ reason.constructor.name !== 'AssertionError') {
146
+ ret += ' because of "' + reason.constructor.name + '"';
147
+ }
143
148
  return ret;
144
149
  }
145
150
  }
@@ -76,17 +76,20 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
76
76
  let schemaOptions = null;
77
77
  let modelNamesInOrder = null;
78
78
 
79
- if (schema != null && schema.instance === 'Embedded' && schema.options.ref) {
80
- const data = {
81
- localField: options.path + '._id',
82
- foreignField: '_id',
83
- justOne: true
84
- };
85
- const res = _getModelNames(doc, schema, modelNameFromQuery, model);
79
+ if (schema != null && schema.instance === 'Embedded') {
80
+ if (schema.options.ref) {
81
+ const data = {
82
+ localField: options.path + '._id',
83
+ foreignField: '_id',
84
+ justOne: true
85
+ };
86
+ const res = _getModelNames(doc, schema, modelNameFromQuery, model);
86
87
 
87
- const unpopulatedValue = mpath.get(options.path, doc);
88
- const id = mpath.get('_id', unpopulatedValue);
89
- addModelNamesToMap(model, map, available, res.modelNames, options, data, id, doc, schemaOptions, unpopulatedValue);
88
+ const unpopulatedValue = mpath.get(options.path, doc);
89
+ const id = mpath.get('_id', unpopulatedValue);
90
+ addModelNamesToMap(model, map, available, res.modelNames, options, data, id, doc, schemaOptions, unpopulatedValue);
91
+ }
92
+ // No-op if no `ref` set. See gh-11538
90
93
  continue;
91
94
  }
92
95
 
@@ -19,13 +19,16 @@ module.exports = function(schematype) {
19
19
  };
20
20
 
21
21
  function createImmutableSetter(path, immutable) {
22
- return function immutableSetter(v) {
22
+ return function immutableSetter(v, _priorVal, _doc, options) {
23
23
  if (this == null || this.$__ == null) {
24
24
  return v;
25
25
  }
26
26
  if (this.isNew) {
27
27
  return v;
28
28
  }
29
+ if (options && options.overwriteImmutable) {
30
+ return v;
31
+ }
29
32
 
30
33
  const _immutable = typeof immutable === 'function' ?
31
34
  immutable.call(this, this) :
@@ -48,8 +48,8 @@ module.exports = function setupTimestamps(schema, timestamps) {
48
48
  currentTime() :
49
49
  this.ownerDocument().constructor.base.now();
50
50
 
51
- if (!skipCreatedAt && this.isNew && createdAt && !this.$__getValue(createdAt) && this.$__isSelected(createdAt)) {
52
- this.$set(createdAt, defaultTimestamp);
51
+ if (!skipCreatedAt && (this.isNew || this.$isSubdocument) && createdAt && !this.$__getValue(createdAt) && this.$__isSelected(createdAt)) {
52
+ this.$set(createdAt, defaultTimestamp, undefined, { overwriteImmutable: true });
53
53
  }
54
54
 
55
55
  if (!skipUpdatedAt && updatedAt && (this.isNew || this.$isModified())) {
package/lib/index.js CHANGED
@@ -267,7 +267,7 @@ Mongoose.prototype.get = Mongoose.prototype.set;
267
267
  * @param {Number} [options.connectTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
268
268
  * @param {Number} [options.socketTimeoutMS=30000] How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
269
269
  * @param {Number} [options.family=0] Passed transparently to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. May be either `0`, `4`, or `6`. `4` means use IPv4 only, `6` means use IPv6 only, `0` means try both.
270
- * @return {Connection} the created Connection object. Connections are thenable, so you can do `await mongoose.createConnection()`
270
+ * @return {Connection} the created Connection object. Connections are not thenable, so you can not `await mongoose.createConnection()`. To await use mongoose.createConnection(uri).asPromise() instead.
271
271
  * @api public
272
272
  */
273
273
 
package/lib/model.js CHANGED
@@ -1074,6 +1074,22 @@ Model.prototype.model = function model(name) {
1074
1074
  return this[modelDbSymbol].model(name);
1075
1075
  };
1076
1076
 
1077
+ /**
1078
+ * Returns another Model instance.
1079
+ *
1080
+ * #### Example:
1081
+ *
1082
+ * const doc = new Tank;
1083
+ * doc.model('User').findById(id, callback);
1084
+ *
1085
+ * @param {String} name model name
1086
+ * @api public
1087
+ */
1088
+
1089
+ Model.prototype.$model = function $model(name) {
1090
+ return this[modelDbSymbol].model(name);
1091
+ };
1092
+
1077
1093
  /**
1078
1094
  * Returns a document with `_id` only if at least one document exists in the database that matches
1079
1095
  * the given `filter`, and `null` otherwise.
@@ -1362,23 +1378,27 @@ Model.createCollection = function createCollection(options, callback) {
1362
1378
  }
1363
1379
 
1364
1380
  const schemaCollation = this &&
1365
- this.schema &&
1366
- this.schema.options &&
1367
- this.schema.options.collation || null;
1381
+ this.schema &&
1382
+ this.schema.options &&
1383
+ this.schema.options.collation;
1368
1384
  if (schemaCollation != null) {
1369
1385
  options = Object.assign({ collation: schemaCollation }, options);
1370
1386
  }
1371
1387
  const capped = this &&
1372
- this.schema &&
1373
- this.schema.options &&
1374
- this.schema.options.capped;
1375
- if (capped) {
1376
- options = Object.assign({ capped: true }, capped, options);
1388
+ this.schema &&
1389
+ this.schema.options &&
1390
+ this.schema.options.capped;
1391
+ if (capped != null) {
1392
+ if (typeof capped === 'number') {
1393
+ options = Object.assign({ capped: true, size: capped }, options);
1394
+ } else if (typeof capped === 'object') {
1395
+ options = Object.assign({ capped: true }, capped, options);
1396
+ }
1377
1397
  }
1378
1398
  const timeseries = this &&
1379
- this.schema &&
1380
- this.schema.options &&
1381
- this.schema.options.timeseries;
1399
+ this.schema &&
1400
+ this.schema.options &&
1401
+ this.schema.options.timeseries;
1382
1402
  if (timeseries != null) {
1383
1403
  options = Object.assign({ timeseries }, options);
1384
1404
  if (options.expireAfterSeconds != null) {
@@ -2148,14 +2168,7 @@ Model.find = function find(conditions, projection, options, callback) {
2148
2168
 
2149
2169
  const mq = new this.Query({}, {}, this, this.$__collection);
2150
2170
  mq.select(projection);
2151
-
2152
2171
  mq.setOptions(options);
2153
- if (this.schema.discriminatorMapping &&
2154
- this.schema.discriminatorMapping.isRoot &&
2155
- mq.selectedInclusively()) {
2156
- // Need to select discriminator key because original schema doesn't have it
2157
- mq.select(this.schema.options.discriminatorKey);
2158
- }
2159
2172
 
2160
2173
  callback = this.$handleCallbackError(callback);
2161
2174
 
@@ -2261,11 +2274,6 @@ Model.findOne = function findOne(conditions, projection, options, callback) {
2261
2274
  const mq = new this.Query({}, {}, this, this.$__collection);
2262
2275
  mq.select(projection);
2263
2276
  mq.setOptions(options);
2264
- if (this.schema.discriminatorMapping &&
2265
- this.schema.discriminatorMapping.isRoot &&
2266
- mq.selectedInclusively()) {
2267
- mq.select(this.schema.options.discriminatorKey);
2268
- }
2269
2277
 
2270
2278
  callback = this.$handleCallbackError(callback);
2271
2279
  return mq.findOne(conditions, callback);
@@ -261,7 +261,17 @@ exports.applyPaths = function applyPaths(fields, schema) {
261
261
  delete fields[plusPath];
262
262
  }
263
263
 
264
- if (typeof type.selected !== 'boolean') return;
264
+ if (typeof type.selected !== 'boolean') {
265
+ return;
266
+ }
267
+
268
+ // If set to 0, we're explicitly excluding the discriminator key. Can't do this for all fields,
269
+ // because we have tests that assert that using `-path` to exclude schema-level `select: true`
270
+ // fields counts as an exclusive projection. See gh-11546
271
+ if (exclude && type.selected && path === schema.options.discriminatorKey && fields[path] != null && !fields[path]) {
272
+ delete fields[path];
273
+ return;
274
+ }
265
275
 
266
276
  if (hasPlusPath) {
267
277
  // forced inclusion
@@ -13,7 +13,6 @@ const SchemaType = require('../schematype');
13
13
  const discriminator = require('../helpers/model/discriminator');
14
14
  const handleIdOption = require('../helpers/schema/handleIdOption');
15
15
  const handleSpreadDoc = require('../helpers/document/handleSpreadDoc');
16
- const util = require('util');
17
16
  const utils = require('../utils');
18
17
  const getConstructor = require('../helpers/discriminator/getConstructor');
19
18
 
@@ -394,7 +393,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
394
393
 
395
394
  if (!Array.isArray(value)) {
396
395
  if (!init && !DocumentArrayPath.options.castNonArrays) {
397
- throw new CastError('DocumentArray', util.inspect(value), this.path, null, this);
396
+ throw new CastError('DocumentArray', value, this.path, null, this);
398
397
  }
399
398
  // gh-2442 mark whole array as modified if we're initializing a doc from
400
399
  // the db and the path isn't an array in the document
@@ -486,8 +485,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
486
485
  // see gh-746
487
486
  rawArray[i] = subdoc;
488
487
  } catch (error) {
489
- const valueInErrorMessage = util.inspect(rawArray[i]);
490
- throw new CastError('embedded', valueInErrorMessage,
488
+ throw new CastError('embedded', rawArray[i],
491
489
  value[arrayPathSymbol], error, this);
492
490
  }
493
491
  }
package/lib/schema.js CHANGED
@@ -54,7 +54,7 @@ let id = 0;
54
54
  * - [autoCreate](/docs/guide.html#autoCreate): bool - defaults to null (which means use the connection's autoCreate option)
55
55
  * - [bufferCommands](/docs/guide.html#bufferCommands): bool - defaults to true
56
56
  * - [bufferTimeoutMS](/docs/guide.html#bufferTimeoutMS): number - defaults to 10000 (10 seconds). If `bufferCommands` is enabled, the amount of time Mongoose will wait for connectivity to be restablished before erroring out.
57
- * - [capped](/docs/guide.html#capped): bool - defaults to false
57
+ * - [capped](/docs/guide.html#capped): bool | number | object - defaults to false
58
58
  * - [collection](/docs/guide.html#collection): string - no default
59
59
  * - [discriminatorKey](/docs/guide.html#discriminatorKey): string - defaults to `__t`
60
60
  * - [id](/docs/guide.html#id): bool - defaults to true
package/lib/schematype.js CHANGED
@@ -1148,7 +1148,7 @@ SchemaType.prototype.getDefault = function(scope, init) {
1148
1148
  * @api private
1149
1149
  */
1150
1150
 
1151
- SchemaType.prototype._applySetters = function(value, scope, init, priorVal) {
1151
+ SchemaType.prototype._applySetters = function(value, scope, init, priorVal, options) {
1152
1152
  let v = value;
1153
1153
  if (init) {
1154
1154
  return v;
@@ -1156,7 +1156,7 @@ SchemaType.prototype._applySetters = function(value, scope, init, priorVal) {
1156
1156
  const setters = this.setters;
1157
1157
 
1158
1158
  for (let i = setters.length - 1; i >= 0; i--) {
1159
- v = setters[i].call(scope, v, priorVal, this);
1159
+ v = setters[i].call(scope, v, priorVal, this, options);
1160
1160
  }
1161
1161
 
1162
1162
  return v;
@@ -311,8 +311,8 @@ const methods = {
311
311
  return this;
312
312
  }
313
313
  const value = methods._cast.call(this, val, i);
314
- arr[i] = value;
315
314
  methods._markModified.call(this, i);
315
+ arr[i] = value;
316
316
  return this;
317
317
  },
318
318
 
@@ -414,9 +414,9 @@ const methods = {
414
414
  }
415
415
 
416
416
  if (!found) {
417
+ this._markModified();
417
418
  rawArray.push(v);
418
419
  this._registerAtomic('$addToSet', v);
419
- this._markModified();
420
420
  [].push.call(added, v);
421
421
  }
422
422
  }, this);
@@ -510,9 +510,9 @@ const methods = {
510
510
 
511
511
  nonAtomicPush() {
512
512
  const values = [].map.call(arguments, this._mapCast, this);
513
+ this._markModified();
513
514
  const ret = [].push.apply(this, values);
514
515
  this._registerAtomic('$set', this);
515
- this._markModified();
516
516
  return ret;
517
517
  },
518
518
 
@@ -530,9 +530,9 @@ const methods = {
530
530
  */
531
531
 
532
532
  pop() {
533
+ this._markModified();
533
534
  const ret = [].pop.call(this);
534
535
  this._registerAtomic('$set', this);
535
- this._markModified();
536
536
  return ret;
537
537
  },
538
538
 
@@ -572,6 +572,7 @@ const methods = {
572
572
  const cur = this[arrayParentSymbol].get(this[arrayPathSymbol]);
573
573
  let i = cur.length;
574
574
  let mem;
575
+ this._markModified();
575
576
 
576
577
  while (i--) {
577
578
  mem = cur[i];
@@ -595,7 +596,6 @@ const methods = {
595
596
  this._registerAtomic('$pullAll', values);
596
597
  }
597
598
 
598
- this._markModified();
599
599
 
600
600
  // Might have modified child paths and then pulled, like
601
601
  // `doc.children[1].name = 'test';` followed by
@@ -657,7 +657,7 @@ const methods = {
657
657
  undefined, { skipDocumentArrayCast: true });
658
658
  let ret;
659
659
  const atomics = this[arrayAtomicsSymbol];
660
-
660
+ this._markModified();
661
661
  if (isOverwrite) {
662
662
  atomic.$each = values;
663
663
 
@@ -684,7 +684,6 @@ const methods = {
684
684
  }
685
685
 
686
686
  this._registerAtomic('$push', atomic);
687
- this._markModified();
688
687
  return ret;
689
688
  },
690
689
 
@@ -737,8 +736,8 @@ const methods = {
737
736
  return this;
738
737
  }
739
738
  const value = methods._cast.call(this, val, i);
740
- arr[i] = value;
741
739
  methods._markModified.call(this, i);
740
+ arr[i] = value;
742
741
  return this;
743
742
  },
744
743
 
@@ -763,9 +762,9 @@ const methods = {
763
762
 
764
763
  shift() {
765
764
  const arr = utils.isMongooseArray(this) ? this.__array : this;
765
+ this._markModified();
766
766
  const ret = [].shift.call(arr);
767
767
  this._registerAtomic('$set', this);
768
- this._markModified();
769
768
  return ret;
770
769
  },
771
770
 
@@ -890,9 +889,9 @@ const methods = {
890
889
  }
891
890
 
892
891
  const arr = utils.isMongooseArray(this) ? this.__array : this;
892
+ this._markModified();
893
893
  [].unshift.apply(arr, values);
894
894
  this._registerAtomic('$set', this);
895
- this._markModified();
896
895
  return this.length;
897
896
  }
898
897
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "6.3.0",
4
+ "version": "6.3.1",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "bson": "^4.2.2",
22
+ "bson": "^4.6.2",
23
23
  "kareem": "2.3.5",
24
24
  "mongodb": "4.5.0",
25
25
  "mpath": "0.8.4",
package/tsconfig.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "compilerOptions": {
3
+ "strictNullChecks": true,
3
4
  "paths": {
4
5
  "mongoose" : ["./types/index.d.ts"]
5
6
  }
6
7
  },
7
- "strictNullChecks": true
8
+ "include": ["types/*"]
8
9
  }
@@ -197,7 +197,7 @@ declare module 'mongoose' {
197
197
  * async function executes successfully and attempt to retry if
198
198
  * there was a retryable error.
199
199
  */
200
- transaction<U = any>(fn: (session: mongodb.ClientSession) => Promise<U>): Promise<U>;
200
+ transaction(fn: (session: mongodb.ClientSession) => Promise<any>): Promise<void>;
201
201
 
202
202
  /** Switches to a different database using the same connection pool. */
203
203
  useDb(name: string, options?: { useCache?: boolean, noListener?: boolean }): Connection;
@@ -206,7 +206,7 @@ declare module 'mongoose' {
206
206
  readonly user: string;
207
207
 
208
208
  /** Watches the entire underlying database for changes. Similar to [`Model.watch()`](/docs/api/model.html#model_Model.watch). */
209
- watch<ResultType = any>(pipeline?: Array<any>, options?: mongodb.ChangeStreamOptions): mongodb.ChangeStream<ResultType>;
209
+ watch<ResultType extends mongodb.Document = any>(pipeline?: Array<any>, options?: mongodb.ChangeStreamOptions): mongodb.ChangeStream<ResultType>;
210
210
  }
211
211
 
212
212
  }
@@ -49,6 +49,9 @@ declare module 'mongoose' {
49
49
  /** Marks a path as valid, removing existing validation errors. */
50
50
  $markValid(path: string): void;
51
51
 
52
+ /** Returns the model with the given name on this document's associated connection. */
53
+ $model<ModelType = Model<unknown>>(name: string): ModelType;
54
+
52
55
  /**
53
56
  * A string containing the current operation that Mongoose is executing
54
57
  * on this document. Can be `null`, `'save'`, `'validate'`, or `'remove'`.
@@ -169,9 +172,6 @@ declare module 'mongoose' {
169
172
  /** The name of the model */
170
173
  modelName: string;
171
174
 
172
- /** Returns the model with the given name on this document's associated connection. */
173
- model<ModelType = Model<unknown>>(name: string): ModelType;
174
-
175
175
  /**
176
176
  * Overwrite all values in this document with the values of `obj`, except
177
177
  * for immutable properties. Behaves similarly to `set()`, except for it
package/types/index.d.ts CHANGED
@@ -183,7 +183,7 @@ declare module 'mongoose' {
183
183
  * section collection.js
184
184
  * http://mongoosejs.com/docs/api.html#collection-js
185
185
  */
186
- interface CollectionBase<T> extends mongodb.Collection<T> {
186
+ interface CollectionBase<T extends mongodb.Document> extends mongodb.Collection<T> {
187
187
  /*
188
188
  * Abstract methods. Some of these are already defined on the
189
189
  * mongodb.Collection interface so they've been commented out.
@@ -205,7 +205,7 @@ declare module 'mongoose' {
205
205
  * http://mongoosejs.com/docs/api.html#drivers-node-mongodb-native-collection-js
206
206
  */
207
207
  let Collection: Collection;
208
- interface Collection<T = AnyObject> extends CollectionBase<T> {
208
+ interface Collection<T extends mongodb.Document = mongodb.Document> extends CollectionBase<T> {
209
209
  /**
210
210
  * Collection constructor
211
211
  * @param name name of the collection
@@ -317,8 +317,8 @@ declare module 'mongoose' {
317
317
  * mongoose will not create the collection for the model until any documents are
318
318
  * created. Use this method to create the collection explicitly.
319
319
  */
320
- createCollection<T>(options?: mongodb.CreateCollectionOptions & Pick<SchemaOptions, 'expires'>): Promise<mongodb.Collection<T>>;
321
- createCollection<T>(options: mongodb.CreateCollectionOptions & Pick<SchemaOptions, 'expires'> | null, callback: Callback<mongodb.Collection<T>>): void;
320
+ createCollection<T extends mongodb.Document>(options?: mongodb.CreateCollectionOptions & Pick<SchemaOptions, 'expires'>): Promise<mongodb.Collection<T>>;
321
+ createCollection<T extends mongodb.Document>(options: mongodb.CreateCollectionOptions & Pick<SchemaOptions, 'expires'> | null, callback: Callback<mongodb.Collection<T>>): void;
322
322
 
323
323
  /**
324
324
  * Similar to `ensureIndexes()`, except for it uses the [`createIndex`](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#createIndex)
@@ -467,7 +467,7 @@ declare module 'mongoose' {
467
467
  validate(optional: any, pathsToValidate: string[], callback?: CallbackWithoutResult): Promise<void>;
468
468
 
469
469
  /** Watches the underlying collection for changes using [MongoDB change streams](https://docs.mongodb.com/manual/changeStreams/). */
470
- watch<ResultType = any>(pipeline?: Array<Record<string, unknown>>, options?: mongodb.ChangeStreamOptions): mongodb.ChangeStream<ResultType>;
470
+ watch<ResultType extends mongodb.Document = any>(pipeline?: Array<Record<string, unknown>>, options?: mongodb.ChangeStreamOptions): mongodb.ChangeStream<ResultType>;
471
471
 
472
472
  /** Adds a `$where` clause to this query */
473
473
  $where(argument: string | Function): QueryWithHelpers<Array<HydratedDocument<T, TMethodsAndOverrides, TVirtuals>>, HydratedDocument<T, TMethodsAndOverrides, TVirtuals>, TQueryHelpers, T>;
@@ -789,6 +789,8 @@ declare module 'mongoose' {
789
789
  model?: string | Model<any>;
790
790
  /** optional query options like sort, limit, etc */
791
791
  options?: any;
792
+ /** correct limit on populated array */
793
+ perDocumentLimit?: number;
792
794
  /** optional boolean, set to `false` to allow populating paths that aren't in the schema */
793
795
  strictPopulate?: boolean;
794
796
  /** deep populate */
@@ -975,13 +977,13 @@ declare module 'mongoose' {
975
977
  virtual<T = HydratedDocument<DocType, TInstanceMethods>>(
976
978
  name: string,
977
979
  options?: VirtualTypeOptions<T, DocType>
978
- ): VirtualType;
980
+ ): VirtualType<T>;
979
981
 
980
982
  /** Object of currently defined virtuals on this schema */
981
983
  virtuals: any;
982
984
 
983
985
  /** Returns the virtual type with the given `name`. */
984
- virtualpath(name: string): VirtualType | null;
986
+ virtualpath<T = HydratedDocument<DocType, TInstanceMethods>>(name: string): VirtualType<T> | null;
985
987
  }
986
988
 
987
989
  type NumberSchemaDefinition = typeof Number | 'number' | 'Number' | typeof Schema.Types.Number;
@@ -1296,7 +1298,7 @@ declare module 'mongoose' {
1296
1298
  [extra: string]: any;
1297
1299
  }
1298
1300
 
1299
- class VirtualType {
1301
+ class VirtualType<HydratedDocType> {
1300
1302
  /** Applies getters to `value`. */
1301
1303
  applyGetters(value: any, doc: Document): any;
1302
1304
 
@@ -1304,10 +1306,10 @@ declare module 'mongoose' {
1304
1306
  applySetters(value: any, doc: Document): any;
1305
1307
 
1306
1308
  /** Adds a custom getter to this virtual. */
1307
- get(fn: Function): this;
1309
+ get<T = HydratedDocType>(fn: (this: T, value: any, virtualType: VirtualType<T>, doc: T) => any): this;
1308
1310
 
1309
1311
  /** Adds a custom setter to this virtual. */
1310
- set(fn: Function): this;
1312
+ set<T = HydratedDocType>(fn: (this: T, value: any, virtualType: VirtualType<T>, doc: T) => void): this;
1311
1313
  }
1312
1314
 
1313
1315
  namespace Schema {