mongoose 8.1.3 → 8.2.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/lib/aggregate.js CHANGED
@@ -1019,8 +1019,8 @@ Aggregate.prototype.exec = async function exec() {
1019
1019
  const model = this._model;
1020
1020
  const collection = this._model.collection;
1021
1021
 
1022
- applyGlobalMaxTimeMS(this.options, model);
1023
- applyGlobalDiskUse(this.options, model);
1022
+ applyGlobalMaxTimeMS(this.options, model.db.options, model.base.options);
1023
+ applyGlobalDiskUse(this.options, model.db.options, model.base.options);
1024
1024
 
1025
1025
  if (this.options && this.options.cursor) {
1026
1026
  return new AggregationCursor(this);
package/lib/connection.js CHANGED
@@ -443,6 +443,28 @@ Connection.prototype.createCollections = async function createCollections(option
443
443
  return result;
444
444
  };
445
445
 
446
+ /**
447
+ * A convenience wrapper for `connection.client.withSession()`.
448
+ *
449
+ * #### Example:
450
+ *
451
+ * await conn.withSession(async session => {
452
+ * const doc = await TestModel.findOne().session(session);
453
+ * });
454
+ *
455
+ * @method withSession
456
+ * @param {Function} executor called with 1 argument: a `ClientSession` instance
457
+ * @return {Promise} resolves to the return value of the executor function
458
+ * @api public
459
+ */
460
+
461
+ Connection.prototype.withSession = async function withSession(executor) {
462
+ if (arguments.length === 0) {
463
+ throw new Error('Please provide an executor function');
464
+ }
465
+ return await this.client.withSession(executor);
466
+ };
467
+
446
468
  /**
447
469
  * _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://www.mongodb.com/docs/manual/release-notes/3.6/#client-sessions)
448
470
  * for benefits like causal consistency, [retryable writes](https://www.mongodb.com/docs/manual/core/retryable-writes/),
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ /*!
4
+ * ignore
5
+ */
6
+
7
+ const queryOperations = Object.freeze([
8
+ // Read
9
+ 'countDocuments',
10
+ 'distinct',
11
+ 'estimatedDocumentCount',
12
+ 'find',
13
+ 'findOne',
14
+ // Update
15
+ 'findOneAndReplace',
16
+ 'findOneAndUpdate',
17
+ 'replaceOne',
18
+ 'updateMany',
19
+ 'updateOne',
20
+ // Delete
21
+ 'deleteMany',
22
+ 'deleteOne',
23
+ 'findOneAndDelete'
24
+ ]);
25
+
26
+ exports.queryOperations = queryOperations;
27
+
28
+ /*!
29
+ * ignore
30
+ */
31
+
32
+ const queryMiddlewareFunctions = queryOperations.concat([
33
+ 'validate'
34
+ ]);
35
+
36
+ exports.queryMiddlewareFunctions = queryMiddlewareFunctions;
package/lib/document.js CHANGED
@@ -694,7 +694,6 @@ Document.prototype.$__init = function(doc, opts) {
694
694
  init(this, doc, this._doc, opts);
695
695
 
696
696
  markArraySubdocsPopulated(this, opts.populated);
697
-
698
697
  this.$emit('init', this);
699
698
  this.constructor.emit('init', this);
700
699
 
@@ -703,7 +702,6 @@ Document.prototype.$__init = function(doc, opts) {
703
702
  null;
704
703
 
705
704
  applyDefaults(this, this.$__.selected, this.$__.exclude, hasIncludedChildren, false, this.$__.skipDefaults);
706
-
707
705
  return this;
708
706
  };
709
707
 
@@ -746,7 +744,6 @@ function init(self, obj, doc, opts, prefix) {
746
744
  }
747
745
  path = prefix + i;
748
746
  schemaType = docSchema.path(path);
749
-
750
747
  // Should still work if not a model-level discriminator, but should not be
751
748
  // necessary. This is *only* to catch the case where we queried using the
752
749
  // base model and the discriminated model has a projection
@@ -770,15 +767,14 @@ function init(self, obj, doc, opts, prefix) {
770
767
  }
771
768
  } else {
772
769
  // Retain order when overwriting defaults
773
- if (doc.hasOwnProperty(i) && obj[i] !== void 0) {
770
+ if (doc.hasOwnProperty(i) && obj[i] !== void 0 && !opts.hydratedPopulatedDocs) {
774
771
  delete doc[i];
775
772
  }
776
773
  if (obj[i] === null) {
777
774
  doc[i] = schemaType._castNullish(null);
778
775
  } else if (obj[i] !== undefined) {
779
776
  const wasPopulated = obj[i].$__ == null ? null : obj[i].$__.wasPopulated;
780
-
781
- if (schemaType && !wasPopulated) {
777
+ if ((schemaType && !wasPopulated) && !opts.hydratedPopulatedDocs) {
782
778
  try {
783
779
  if (opts && opts.setters) {
784
780
  // Call applySetters with `init = false` because otherwise setters are a noop
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const middlewareFunctions = require('../query/applyQueryMiddleware').middlewareFunctions;
3
+ const middlewareFunctions = require('../../constants').queryMiddlewareFunctions;
4
4
  const promiseOrCallback = require('../promiseOrCallback');
5
5
 
6
6
  module.exports = function applyStaticHooks(model, hooks, statics) {
@@ -2,12 +2,12 @@
2
2
 
3
3
  const utils = require('../../utils');
4
4
 
5
- function applyGlobalMaxTimeMS(options, model) {
6
- applyGlobalOption(options, model, 'maxTimeMS');
5
+ function applyGlobalMaxTimeMS(options, connectionOptions, baseOptions) {
6
+ applyGlobalOption(options, connectionOptions, baseOptions, 'maxTimeMS');
7
7
  }
8
8
 
9
- function applyGlobalDiskUse(options, model) {
10
- applyGlobalOption(options, model, 'allowDiskUse');
9
+ function applyGlobalDiskUse(options, connectionOptions, baseOptions) {
10
+ applyGlobalOption(options, connectionOptions, baseOptions, 'allowDiskUse');
11
11
  }
12
12
 
13
13
  module.exports = {
@@ -16,14 +16,14 @@ module.exports = {
16
16
  };
17
17
 
18
18
 
19
- function applyGlobalOption(options, model, optionName) {
19
+ function applyGlobalOption(options, connectionOptions, baseOptions, optionName) {
20
20
  if (utils.hasUserDefinedProperty(options, optionName)) {
21
21
  return;
22
22
  }
23
23
 
24
- if (utils.hasUserDefinedProperty(model.db.options, optionName)) {
25
- options[optionName] = model.db.options[optionName];
26
- } else if (utils.hasUserDefinedProperty(model.base.options, optionName)) {
27
- options[optionName] = model.base.options[optionName];
24
+ if (utils.hasUserDefinedProperty(connectionOptions, optionName)) {
25
+ options[optionName] = connectionOptions[optionName];
26
+ } else if (utils.hasUserDefinedProperty(baseOptions, optionName)) {
27
+ options[optionName] = baseOptions[optionName];
28
28
  }
29
29
  }
@@ -2,8 +2,7 @@
2
2
 
3
3
  const isOperator = require('./isOperator');
4
4
 
5
- module.exports = function castFilterPath(query, schematype, val) {
6
- const ctx = query;
5
+ module.exports = function castFilterPath(ctx, schematype, val) {
7
6
  const any$conditionals = Object.keys(val).some(isOperator);
8
7
 
9
8
  if (!any$conditionals) {
@@ -1,20 +1,3 @@
1
1
  'use strict';
2
2
 
3
- module.exports = Object.freeze([
4
- // Read
5
- 'countDocuments',
6
- 'distinct',
7
- 'estimatedDocumentCount',
8
- 'find',
9
- 'findOne',
10
- // Update
11
- 'findOneAndReplace',
12
- 'findOneAndUpdate',
13
- 'replaceOne',
14
- 'updateMany',
15
- 'updateOne',
16
- // Delete
17
- 'deleteMany',
18
- 'deleteOne',
19
- 'findOneAndDelete'
20
- ]);
3
+ module.exports = require('../../constants').queryMiddlewareFunctions;
package/lib/model.js CHANGED
@@ -23,7 +23,6 @@ const VersionError = require('./error/version');
23
23
  const ParallelSaveError = require('./error/parallelSave');
24
24
  const applyDefaultsHelper = require('./helpers/document/applyDefaults');
25
25
  const applyDefaultsToPOJO = require('./helpers/model/applyDefaultsToPOJO');
26
- const applyQueryMiddleware = require('./helpers/query/applyQueryMiddleware');
27
26
  const applyHooks = require('./helpers/model/applyHooks');
28
27
  const applyMethods = require('./helpers/model/applyMethods');
29
28
  const applyProjection = require('./helpers/projection/applyProjection');
@@ -1415,6 +1414,18 @@ Model.createCollection = async function createCollection(options) {
1415
1414
  throw new MongooseError('Model.createCollection() no longer accepts a callback');
1416
1415
  }
1417
1416
 
1417
+ const shouldSkip = await new Promise((resolve, reject) => {
1418
+ this.hooks.execPre('createCollection', this, [options], (err) => {
1419
+ if (err != null) {
1420
+ if (err instanceof Kareem.skipWrappedFunction) {
1421
+ return resolve(true);
1422
+ }
1423
+ return reject(err);
1424
+ }
1425
+ resolve();
1426
+ });
1427
+ });
1428
+
1418
1429
  const collectionOptions = this &&
1419
1430
  this.schema &&
1420
1431
  this.schema.options &&
@@ -1468,13 +1479,32 @@ Model.createCollection = async function createCollection(options) {
1468
1479
  }
1469
1480
 
1470
1481
  try {
1471
- await this.db.createCollection(this.$__collection.collectionName, options);
1482
+ if (!shouldSkip) {
1483
+ await this.db.createCollection(this.$__collection.collectionName, options);
1484
+ }
1472
1485
  } catch (err) {
1473
-
1474
1486
  if (err != null && (err.name !== 'MongoServerError' || err.code !== 48)) {
1475
- throw err;
1487
+ await new Promise((resolve, reject) => {
1488
+ const _opts = { error: err };
1489
+ this.hooks.execPost('createCollection', this, [null], _opts, (err) => {
1490
+ if (err != null) {
1491
+ return reject(err);
1492
+ }
1493
+ resolve();
1494
+ });
1495
+ });
1476
1496
  }
1477
1497
  }
1498
+
1499
+ await new Promise((resolve, reject) => {
1500
+ this.hooks.execPost('createCollection', this, [this.$__collection], (err) => {
1501
+ if (err != null) {
1502
+ return reject(err);
1503
+ }
1504
+ resolve();
1505
+ });
1506
+ });
1507
+
1478
1508
  return this.$__collection;
1479
1509
  };
1480
1510
 
@@ -3428,44 +3458,62 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
3428
3458
  throw new MongooseError('Model.bulkWrite() no longer accepts a callback');
3429
3459
  }
3430
3460
  options = options || {};
3461
+
3462
+ const shouldSkip = await new Promise((resolve, reject) => {
3463
+ this.hooks.execPre('bulkWrite', this, [ops, options], (err) => {
3464
+ if (err != null) {
3465
+ if (err instanceof Kareem.skipWrappedFunction) {
3466
+ return resolve(err);
3467
+ }
3468
+ return reject(err);
3469
+ }
3470
+ resolve();
3471
+ });
3472
+ });
3473
+
3474
+ if (shouldSkip) {
3475
+ return shouldSkip.args[0];
3476
+ }
3477
+
3431
3478
  const ordered = options.ordered == null ? true : options.ordered;
3432
3479
 
3480
+ if (ops.length === 0) {
3481
+ return getDefaultBulkwriteResult();
3482
+ }
3483
+
3433
3484
  const validations = ops.map(op => castBulkWrite(this, op, options));
3434
3485
 
3435
- return new Promise((resolve, reject) => {
3436
- if (ordered) {
3486
+ let res = null;
3487
+ if (ordered) {
3488
+ await new Promise((resolve, reject) => {
3437
3489
  each(validations, (fn, cb) => fn(cb), error => {
3438
3490
  if (error) {
3439
3491
  return reject(error);
3440
3492
  }
3441
3493
 
3442
- if (ops.length === 0) {
3443
- return resolve(getDefaultBulkwriteResult());
3444
- }
3445
-
3446
- try {
3447
- this.$__collection.bulkWrite(ops, options, (error, res) => {
3448
- if (error) {
3449
- return reject(error);
3450
- }
3451
-
3452
- resolve(res);
3453
- });
3454
- } catch (err) {
3455
- return reject(err);
3456
- }
3494
+ resolve();
3457
3495
  });
3496
+ });
3458
3497
 
3459
- return;
3498
+ try {
3499
+ res = await this.$__collection.bulkWrite(ops, options);
3500
+ } catch (error) {
3501
+ await new Promise((resolve, reject) => {
3502
+ const _opts = { error: error };
3503
+ this.hooks.execPost('bulkWrite', this, [null], _opts, (err) => {
3504
+ if (err != null) {
3505
+ return reject(err);
3506
+ }
3507
+ resolve();
3508
+ });
3509
+ });
3460
3510
  }
3461
-
3511
+ } else {
3462
3512
  let remaining = validations.length;
3463
3513
  let validOps = [];
3464
3514
  let validationErrors = [];
3465
3515
  const results = [];
3466
- if (remaining === 0) {
3467
- completeUnorderedValidation.call(this);
3468
- } else {
3516
+ await new Promise((resolve) => {
3469
3517
  for (let i = 0; i < validations.length; ++i) {
3470
3518
  validations[i]((err) => {
3471
3519
  if (err == null) {
@@ -3475,56 +3523,74 @@ Model.bulkWrite = async function bulkWrite(ops, options) {
3475
3523
  results[i] = err;
3476
3524
  }
3477
3525
  if (--remaining <= 0) {
3478
- completeUnorderedValidation.call(this);
3526
+ resolve();
3479
3527
  }
3480
3528
  });
3481
3529
  }
3482
- }
3530
+ });
3483
3531
 
3484
3532
  validationErrors = validationErrors.
3485
3533
  sort((v1, v2) => v1.index - v2.index).
3486
3534
  map(v => v.error);
3487
3535
 
3488
- function completeUnorderedValidation() {
3489
- const validOpIndexes = validOps;
3490
- validOps = validOps.sort().map(index => ops[index]);
3536
+ const validOpIndexes = validOps;
3537
+ validOps = validOps.sort().map(index => ops[index]);
3491
3538
 
3492
- if (validOps.length === 0) {
3493
- return resolve(getDefaultBulkwriteResult());
3494
- }
3539
+ if (validOps.length === 0) {
3540
+ return getDefaultBulkwriteResult();
3541
+ }
3495
3542
 
3496
- this.$__collection.bulkWrite(validOps, options, (error, res) => {
3497
- if (error) {
3498
- if (validationErrors.length > 0) {
3499
- error.mongoose = error.mongoose || {};
3500
- error.mongoose.validationErrors = validationErrors;
3501
- }
3543
+ let error;
3544
+ [res, error] = await this.$__collection.bulkWrite(validOps, options).
3545
+ then(res => ([res, null])).
3546
+ catch(err => ([null, err]));
3502
3547
 
3503
- return reject(error);
3504
- }
3548
+ if (error) {
3549
+ if (validationErrors.length > 0) {
3550
+ error.mongoose = error.mongoose || {};
3551
+ error.mongoose.validationErrors = validationErrors;
3552
+ }
3505
3553
 
3506
- for (let i = 0; i < validOpIndexes.length; ++i) {
3507
- results[validOpIndexes[i]] = null;
3508
- }
3509
- if (validationErrors.length > 0) {
3510
- if (options.throwOnValidationError) {
3511
- return reject(new MongooseBulkWriteError(
3512
- validationErrors,
3513
- results,
3514
- res,
3515
- 'bulkWrite'
3516
- ));
3517
- } else {
3518
- res.mongoose = res.mongoose || {};
3519
- res.mongoose.validationErrors = validationErrors;
3520
- res.mongoose.results = results;
3554
+ await new Promise((resolve, reject) => {
3555
+ const _opts = { error: error };
3556
+ this.hooks.execPost('bulkWrite', this, [null], _opts, (err) => {
3557
+ if (err != null) {
3558
+ return reject(err);
3521
3559
  }
3522
- }
3523
-
3524
- resolve(res);
3560
+ resolve();
3561
+ });
3525
3562
  });
3526
3563
  }
3564
+
3565
+ for (let i = 0; i < validOpIndexes.length; ++i) {
3566
+ results[validOpIndexes[i]] = null;
3567
+ }
3568
+ if (validationErrors.length > 0) {
3569
+ if (options.throwOnValidationError) {
3570
+ throw new MongooseBulkWriteError(
3571
+ validationErrors,
3572
+ results,
3573
+ res,
3574
+ 'bulkWrite'
3575
+ );
3576
+ } else {
3577
+ res.mongoose = res.mongoose || {};
3578
+ res.mongoose.validationErrors = validationErrors;
3579
+ res.mongoose.results = results;
3580
+ }
3581
+ }
3582
+ }
3583
+
3584
+ await new Promise((resolve, reject) => {
3585
+ this.hooks.execPost('bulkWrite', this, [res], (err) => {
3586
+ if (err != null) {
3587
+ return reject(err);
3588
+ }
3589
+ resolve();
3590
+ });
3527
3591
  });
3592
+
3593
+ return res;
3528
3594
  };
3529
3595
 
3530
3596
  /**
@@ -3830,6 +3896,7 @@ Model.buildBulkWriteOperations = function buildBulkWriteOperations(documents, op
3830
3896
  * @param {Object|String|String[]} [projection] optional projection containing which fields should be selected for this document
3831
3897
  * @param {Object} [options] optional options
3832
3898
  * @param {Boolean} [options.setters=false] if true, apply schema setters when hydrating
3899
+ * @param {Boolean} [options.hydratedPopulatedDocs=false] if true, populates the docs if passing pre-populated data
3833
3900
  * @return {Document} document instance
3834
3901
  * @api public
3835
3902
  */
@@ -3843,7 +3910,6 @@ Model.hydrate = function(obj, projection, options) {
3843
3910
  }
3844
3911
  obj = applyProjection(obj, projection);
3845
3912
  }
3846
-
3847
3913
  const document = require('./queryHelpers').createModel(this, obj, projection);
3848
3914
  document.$init(obj, options);
3849
3915
  return document;
@@ -4774,7 +4840,7 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
4774
4840
  Object.setPrototypeOf(model.Query.prototype, Query.prototype);
4775
4841
  model.Query.base = Query.base;
4776
4842
  model.Query.prototype.constructor = Query;
4777
- applyQueryMiddleware(model.Query, model);
4843
+ model._applyQueryMiddleware();
4778
4844
  applyQueryMethods(model, schema.query);
4779
4845
 
4780
4846
  return model;
@@ -4861,6 +4927,35 @@ Model.__subclass = function subclass(conn, schema, collection) {
4861
4927
  return Model;
4862
4928
  };
4863
4929
 
4930
+ /**
4931
+ * Apply changes made to this model's schema after this model was compiled.
4932
+ * By default, adding virtuals and other properties to a schema after the model is compiled does nothing.
4933
+ * Call this function to apply virtuals and properties that were added later.
4934
+ *
4935
+ * #### Example:
4936
+ *
4937
+ * const schema = new mongoose.Schema({ field: String });
4938
+ * const TestModel = mongoose.model('Test', schema);
4939
+ * TestModel.schema.virtual('myVirtual').get(function() {
4940
+ * return this.field + ' from myVirtual';
4941
+ * });
4942
+ * const doc = new TestModel({ field: 'Hello' });
4943
+ * doc.myVirtual; // undefined
4944
+ *
4945
+ * TestModel.recompileSchema();
4946
+ * doc.myVirtual; // 'Hello from myVirtual'
4947
+ *
4948
+ * @return {undefined}
4949
+ * @api public
4950
+ * @memberOf Model
4951
+ * @static
4952
+ * @method recompileSchema
4953
+ */
4954
+
4955
+ Model.recompileSchema = function recompileSchema() {
4956
+ this.prototype.$__setSchema(this.schema);
4957
+ };
4958
+
4864
4959
  /**
4865
4960
  * Helper for console.log. Given a model named 'MyModel', returns the string
4866
4961
  * `'Model { MyModel }'`.
@@ -4883,6 +4978,41 @@ if (util.inspect.custom) {
4883
4978
  Model[util.inspect.custom] = Model.inspect;
4884
4979
  }
4885
4980
 
4981
+ /*!
4982
+ * Applies query middleware from this model's schema to this model's
4983
+ * Query constructor.
4984
+ */
4985
+
4986
+ Model._applyQueryMiddleware = function _applyQueryMiddleware() {
4987
+ const Query = this.Query;
4988
+ const queryMiddleware = this.schema.s.hooks.filter(hook => {
4989
+ const contexts = _getContexts(hook);
4990
+ if (hook.name === 'validate') {
4991
+ return !!contexts.query;
4992
+ }
4993
+ if (hook.name === 'deleteOne' || hook.name === 'updateOne') {
4994
+ return !!contexts.query || Object.keys(contexts).length === 0;
4995
+ }
4996
+ if (hook.query != null || hook.document != null) {
4997
+ return !!hook.query;
4998
+ }
4999
+ return true;
5000
+ });
5001
+
5002
+ Query.prototype._queryMiddleware = queryMiddleware;
5003
+ };
5004
+
5005
+ function _getContexts(hook) {
5006
+ const ret = {};
5007
+ if (hook.hasOwnProperty('query')) {
5008
+ ret.query = hook.query;
5009
+ }
5010
+ if (hook.hasOwnProperty('document')) {
5011
+ ret.document = hook.document;
5012
+ }
5013
+ return ret;
5014
+ }
5015
+
4886
5016
  /*!
4887
5017
  * Module exports.
4888
5018
  */
package/lib/query.js CHANGED
@@ -19,7 +19,6 @@ const castArrayFilters = require('./helpers/update/castArrayFilters');
19
19
  const castNumber = require('./cast/number');
20
20
  const castUpdate = require('./helpers/query/castUpdate');
21
21
  const clone = require('./helpers/clone');
22
- const completeMany = require('./helpers/query/completeMany');
23
22
  const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue');
24
23
  const helpers = require('./queryHelpers');
25
24
  const immediate = require('./helpers/immediate');
@@ -40,7 +39,7 @@ const specialProperties = require('./helpers/specialProperties');
40
39
  const updateValidators = require('./helpers/updateValidators');
41
40
  const util = require('util');
42
41
  const utils = require('./utils');
43
- const validOps = require('./helpers/query/validOps');
42
+ const queryMiddlewareFunctions = require('./constants').queryMiddlewareFunctions;
44
43
 
45
44
  const queryOptionMethods = new Set([
46
45
  'allowDiskUse',
@@ -457,7 +456,7 @@ Query.prototype.slice = function() {
457
456
  * ignore
458
457
  */
459
458
 
460
- const validOpsSet = new Set(validOps);
459
+ const validOpsSet = new Set(queryMiddlewareFunctions);
461
460
 
462
461
  Query.prototype._validateOp = function() {
463
462
  if (this.op != null && !validOpsSet.has(this.op)) {
@@ -2233,8 +2232,8 @@ Query.prototype._find = async function _find() {
2233
2232
  const _this = this;
2234
2233
  const userProvidedFields = _this._userProvidedFields || {};
2235
2234
 
2236
- applyGlobalMaxTimeMS(this.options, this.model);
2237
- applyGlobalDiskUse(this.options, this.model);
2235
+ applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
2236
+ applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
2238
2237
 
2239
2238
  // Separate options to pass down to `completeMany()` in case we need to
2240
2239
  // set a session on the document
@@ -2271,7 +2270,7 @@ Query.prototype._find = async function _find() {
2271
2270
  }
2272
2271
  return mongooseOptions.lean ?
2273
2272
  _completeManyLean(_this.model.schema, docs, null, completeManyOptions) :
2274
- completeMany(_this.model, docs, fields, userProvidedFields, completeManyOptions);
2273
+ _this._completeMany(docs, fields, userProvidedFields, completeManyOptions);
2275
2274
  }
2276
2275
  const pop = helpers.preparePopulationOptionsMQ(_this, mongooseOptions);
2277
2276
 
@@ -2279,7 +2278,7 @@ Query.prototype._find = async function _find() {
2279
2278
  return _this.model.populate(docs, pop);
2280
2279
  }
2281
2280
 
2282
- docs = await completeMany(_this.model, docs, fields, userProvidedFields, completeManyOptions);
2281
+ docs = await _this._completeMany(docs, fields, userProvidedFields, completeManyOptions);
2283
2282
  await this.model.populate(docs, pop);
2284
2283
 
2285
2284
  return docs;
@@ -2473,6 +2472,36 @@ Query.prototype._completeOne = function(doc, res, callback) {
2473
2472
  });
2474
2473
  };
2475
2474
 
2475
+ /**
2476
+ * Given a model and an array of docs, hydrates all the docs to be instances
2477
+ * of the model. Used to initialize docs returned from the db from `find()`
2478
+ *
2479
+ * @param {Array} docs
2480
+ * @param {Object} fields the projection used, including `select` from schemas
2481
+ * @param {Object} userProvidedFields the user-specified projection
2482
+ * @param {Object} [opts]
2483
+ * @param {Array} [opts.populated]
2484
+ * @param {ClientSession} [opts.session]
2485
+ * @api private
2486
+ */
2487
+
2488
+ Query.prototype._completeMany = async function _completeMany(docs, fields, userProvidedFields, opts) {
2489
+ const model = this.model;
2490
+ return Promise.all(docs.map(doc => new Promise((resolve, reject) => {
2491
+ const rawDoc = doc;
2492
+ doc = helpers.createModel(model, doc, fields, userProvidedFields);
2493
+ if (opts.session != null) {
2494
+ doc.$session(opts.session);
2495
+ }
2496
+ doc.$init(rawDoc, opts, (err) => {
2497
+ if (err != null) {
2498
+ return reject(err);
2499
+ }
2500
+ resolve(doc);
2501
+ });
2502
+ })));
2503
+ };
2504
+
2476
2505
  /**
2477
2506
  * Internal helper to execute a findOne() operation
2478
2507
  *
@@ -2488,8 +2517,8 @@ Query.prototype._findOne = async function _findOne() {
2488
2517
  throw err;
2489
2518
  }
2490
2519
 
2491
- applyGlobalMaxTimeMS(this.options, this.model);
2492
- applyGlobalDiskUse(this.options, this.model);
2520
+ applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
2521
+ applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
2493
2522
 
2494
2523
  const options = this._optionsForExec();
2495
2524
 
@@ -2585,8 +2614,8 @@ Query.prototype._countDocuments = async function _countDocuments() {
2585
2614
  throw this.error();
2586
2615
  }
2587
2616
 
2588
- applyGlobalMaxTimeMS(this.options, this.model);
2589
- applyGlobalDiskUse(this.options, this.model);
2617
+ applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
2618
+ applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
2590
2619
 
2591
2620
  const options = this._optionsForExec();
2592
2621
 
@@ -2754,8 +2783,8 @@ Query.prototype.__distinct = async function __distinct() {
2754
2783
  throw this.error();
2755
2784
  }
2756
2785
 
2757
- applyGlobalMaxTimeMS(this.options, this.model);
2758
- applyGlobalDiskUse(this.options, this.model);
2786
+ applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
2787
+ applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
2759
2788
 
2760
2789
  const options = this._optionsForExec();
2761
2790
  this._applyTranslateAliases(options);
@@ -3247,8 +3276,8 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
3247
3276
  throw this.error();
3248
3277
  }
3249
3278
 
3250
- applyGlobalMaxTimeMS(this.options, this.model);
3251
- applyGlobalDiskUse(this.options, this.model);
3279
+ applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
3280
+ applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
3252
3281
 
3253
3282
  if ('strict' in this.options) {
3254
3283
  this._mongooseOptions.strict = this.options.strict;