mongoose 9.0.1 → 9.1.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.
Files changed (93) hide show
  1. package/lib/aggregate.js +1 -1
  2. package/lib/cast/string.js +1 -1
  3. package/lib/cast.js +7 -15
  4. package/lib/collection.js +2 -2
  5. package/lib/connection.js +20 -14
  6. package/lib/cursor/changeStream.js +5 -5
  7. package/lib/document.js +126 -79
  8. package/lib/drivers/node-mongodb-native/collection.js +33 -126
  9. package/lib/drivers/node-mongodb-native/connection.js +8 -23
  10. package/lib/error/cast.js +1 -1
  11. package/lib/helpers/aggregate/prepareDiscriminatorPipeline.js +4 -4
  12. package/lib/helpers/clone.js +8 -8
  13. package/lib/helpers/common.js +4 -4
  14. package/lib/helpers/cursor/eachAsync.js +1 -1
  15. package/lib/helpers/discriminator/getConstructor.js +1 -1
  16. package/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +1 -1
  17. package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +2 -2
  18. package/lib/helpers/document/applyDefaults.js +1 -1
  19. package/lib/helpers/document/applyTimestamps.js +2 -1
  20. package/lib/helpers/document/applyVirtuals.js +4 -3
  21. package/lib/helpers/document/cleanModifiedSubpaths.js +1 -1
  22. package/lib/helpers/document/compile.js +4 -4
  23. package/lib/helpers/document/getDeepestSubdocumentForPath.js +1 -1
  24. package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +1 -1
  25. package/lib/helpers/indexes/getRelatedIndexes.js +3 -3
  26. package/lib/helpers/model/castBulkWrite.js +5 -9
  27. package/lib/helpers/model/discriminator.js +1 -1
  28. package/lib/helpers/populate/assignRawDocsToIdStructure.js +1 -1
  29. package/lib/helpers/populate/assignVals.js +4 -4
  30. package/lib/helpers/populate/getModelsMapForPopulate.js +25 -23
  31. package/lib/helpers/populate/getSchemaTypes.js +6 -7
  32. package/lib/helpers/printJestWarning.js +1 -1
  33. package/lib/helpers/processConnectionOptions.js +1 -1
  34. package/lib/helpers/query/castUpdate.js +12 -12
  35. package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +2 -2
  36. package/lib/helpers/query/handleImmutable.js +2 -2
  37. package/lib/helpers/query/sanitizeFilter.js +1 -1
  38. package/lib/helpers/schema/applyPlugins.js +1 -1
  39. package/lib/helpers/schema/applyReadConcern.js +1 -1
  40. package/lib/helpers/schema/applyWriteConcern.js +4 -2
  41. package/lib/helpers/schema/getIndexes.js +3 -3
  42. package/lib/helpers/schema/getSubdocumentStrictValue.js +1 -1
  43. package/lib/helpers/schema/handleIdOption.js +1 -1
  44. package/lib/helpers/schema/idGetter.js +1 -1
  45. package/lib/helpers/schematype/handleImmutable.js +1 -1
  46. package/lib/helpers/setDefaultsOnInsert.js +2 -5
  47. package/lib/helpers/timestamps/setDocumentTimestamps.js +2 -2
  48. package/lib/helpers/timestamps/setupTimestamps.js +2 -2
  49. package/lib/helpers/update/applyTimestampsToUpdate.js +10 -9
  50. package/lib/helpers/update/castArrayFilters.js +4 -4
  51. package/lib/helpers/update/decorateUpdateWithVersionKey.js +1 -1
  52. package/lib/helpers/updateValidators.js +4 -4
  53. package/lib/model.js +42 -48
  54. package/lib/mongoose.js +5 -5
  55. package/lib/options/virtualOptions.js +1 -1
  56. package/lib/plugins/saveSubdocs.js +2 -2
  57. package/lib/plugins/trackTransaction.js +3 -4
  58. package/lib/query.js +62 -59
  59. package/lib/queryHelpers.js +9 -12
  60. package/lib/schema/array.js +10 -12
  61. package/lib/schema/buffer.js +6 -6
  62. package/lib/schema/documentArray.js +15 -23
  63. package/lib/schema/documentArrayElement.js +3 -3
  64. package/lib/schema/map.js +1 -1
  65. package/lib/schema/mixed.js +2 -2
  66. package/lib/schema/number.js +22 -4
  67. package/lib/schema/objectId.js +1 -1
  68. package/lib/schema/operators/exists.js +1 -1
  69. package/lib/schema/operators/geospatial.js +1 -1
  70. package/lib/schema/string.js +2 -2
  71. package/lib/schema/subdocument.js +9 -12
  72. package/lib/schema/union.js +1 -1
  73. package/lib/schema.js +27 -28
  74. package/lib/schemaType.js +11 -11
  75. package/lib/types/array/index.js +2 -2
  76. package/lib/types/array/methods/index.js +38 -8
  77. package/lib/types/arraySubdocument.js +12 -2
  78. package/lib/types/buffer.js +1 -1
  79. package/lib/types/documentArray/index.js +2 -2
  80. package/lib/types/documentArray/methods/index.js +5 -5
  81. package/lib/types/map.js +8 -8
  82. package/lib/types/subdocument.js +15 -5
  83. package/lib/utils.js +23 -7
  84. package/package.json +3 -2
  85. package/types/index.d.ts +26 -9
  86. package/types/inferrawdoctype.d.ts +9 -3
  87. package/types/inferschematype.d.ts +20 -27
  88. package/types/middlewares.d.ts +11 -0
  89. package/types/models.d.ts +15 -5
  90. package/types/query.d.ts +1 -1
  91. package/types/schemaoptions.d.ts +4 -2
  92. package/types/utility.d.ts +1 -1
  93. package/types/virtuals.d.ts +3 -3
package/lib/query.js CHANGED
@@ -136,7 +136,7 @@ function Query(conditions, options, model, collection) {
136
136
 
137
137
  // this is needed because map reduce returns a model that can be queried, but
138
138
  // all of the queries on said model should be lean
139
- if (this.model && this.model._mapreduce) {
139
+ if (this.model?._mapreduce) {
140
140
  this.lean();
141
141
  }
142
142
 
@@ -156,10 +156,7 @@ function Query(conditions, options, model, collection) {
156
156
  // versions of MongoDB
157
157
  this.$useProjection = true;
158
158
 
159
- const collation = this &&
160
- this.schema &&
161
- this.schema.options &&
162
- this.schema.options.collation || null;
159
+ const collation = this?.schema?.options?.collation || null;
163
160
  if (collation != null) {
164
161
  this.options.collation = collation;
165
162
  }
@@ -169,7 +166,7 @@ function Query(conditions, options, model, collection) {
169
166
  function isEmptyFilter(obj) {
170
167
  if (obj == null) return true;
171
168
  if (typeof obj !== 'object') return true;
172
- if (Object.keys(obj).length === 0) return true;
169
+ if (utils.hasOwnKeys(obj) === false) return true;
173
170
 
174
171
  // Check $and, $or, $nor arrays
175
172
  for (const key of ['$and', '$or', '$nor']) {
@@ -186,7 +183,7 @@ function isEmptyFilter(obj) {
186
183
 
187
184
  // Helper function to check for empty/invalid filter
188
185
  function checkRequireFilter(filter, options) {
189
- if (options && options.requireFilter && isEmptyFilter(filter)) {
186
+ if (options?.requireFilter && isEmptyFilter(filter)) {
190
187
  throw new Error('Empty or invalid filter not allowed with requireFilter enabled');
191
188
  }
192
189
  }
@@ -457,8 +454,8 @@ Query.prototype.clone = function() {
457
454
  * @api public
458
455
  */
459
456
 
460
- Query.prototype.slice = function() {
461
- if (arguments.length === 0) {
457
+ Query.prototype.slice = function(...args) {
458
+ if (args.length === 0) {
462
459
  return this;
463
460
  }
464
461
 
@@ -467,8 +464,8 @@ Query.prototype.slice = function() {
467
464
  let path;
468
465
  let val;
469
466
 
470
- if (arguments.length === 1) {
471
- const arg = arguments[0];
467
+ if (args.length === 1) {
468
+ const arg = args[0];
472
469
  if (typeof arg === 'object' && !Array.isArray(arg)) {
473
470
  const keys = Object.keys(arg);
474
471
  const numKeys = keys.length;
@@ -479,19 +476,19 @@ Query.prototype.slice = function() {
479
476
  }
480
477
  this._ensurePath('slice');
481
478
  path = this._path;
482
- val = arguments[0];
483
- } else if (arguments.length === 2) {
484
- if ('number' === typeof arguments[0]) {
479
+ val = args[0];
480
+ } else if (args.length === 2) {
481
+ if ('number' === typeof args[0]) {
485
482
  this._ensurePath('slice');
486
483
  path = this._path;
487
- val = [arguments[0], arguments[1]];
484
+ val = [args[0], args[1]];
488
485
  } else {
489
- path = arguments[0];
490
- val = arguments[1];
486
+ path = args[0];
487
+ val = args[1];
491
488
  }
492
- } else if (arguments.length === 3) {
493
- path = arguments[0];
494
- val = [arguments[1], arguments[2]];
489
+ } else if (args.length === 3) {
490
+ path = args[0];
491
+ val = [args[1], args[2]];
495
492
  }
496
493
 
497
494
  const p = {};
@@ -2006,7 +2003,7 @@ Query.prototype._fieldsForExec = function() {
2006
2003
  if (this._fields == null) {
2007
2004
  return null;
2008
2005
  }
2009
- if (Object.keys(this._fields).length === 0) {
2006
+ if (utils.hasOwnKeys(this._fields) === false) {
2010
2007
  return null;
2011
2008
  }
2012
2009
  return clone(this._fields);
@@ -2104,10 +2101,7 @@ Query.prototype._optionsForExec = function(model) {
2104
2101
  options.session = asyncLocalStorage.session;
2105
2102
  }
2106
2103
 
2107
- const readPreference = model &&
2108
- model.schema &&
2109
- model.schema.options &&
2110
- model.schema.options.read;
2104
+ const readPreference = model?.schema?.options?.read;
2111
2105
  if (!('readPreference' in options) && readPreference) {
2112
2106
  options.readPreference = readPreference;
2113
2107
  }
@@ -2413,13 +2407,15 @@ Query.prototype._find = async function _find() {
2413
2407
  const mongooseOptions = this._mongooseOptions;
2414
2408
  const userProvidedFields = this._userProvidedFields || {};
2415
2409
 
2416
- applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
2417
- applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
2410
+ const dbOptions = this.model.db.options;
2411
+ const baseOptions = this.model.base.options;
2412
+ applyGlobalMaxTimeMS(this.options, dbOptions, baseOptions);
2413
+ applyGlobalDiskUse(this.options, dbOptions, baseOptions);
2418
2414
 
2419
2415
  // Separate options to pass down to `completeMany()` in case we need to
2420
2416
  // set a session on the document
2421
2417
  const completeManyOptions = {
2422
- session: this && this.options && this.options.session || null,
2418
+ session: this?.options?.session || null,
2423
2419
  lean: mongooseOptions.lean || null
2424
2420
  };
2425
2421
 
@@ -2440,7 +2436,7 @@ Query.prototype._find = async function _find() {
2440
2436
 
2441
2437
  if (!mongooseOptions.populate) {
2442
2438
  const versionKey = this.schema.options.versionKey;
2443
- if (mongooseOptions.lean && mongooseOptions.lean.versionKey === false && versionKey) {
2439
+ if (mongooseOptions.lean?.versionKey === false && versionKey) {
2444
2440
  docs.forEach((doc) => {
2445
2441
  if (versionKey in doc) {
2446
2442
  delete doc[versionKey];
@@ -2561,7 +2557,7 @@ Query.prototype.merge = function(source) {
2561
2557
  utils.merge(this._conditions, { _id: source }, opts);
2562
2558
 
2563
2559
  return this;
2564
- } else if (source && source.$__) {
2560
+ } else if (source?.$__) {
2565
2561
  source = source.toObject(internalToObjectOptions);
2566
2562
  }
2567
2563
 
@@ -2635,7 +2631,7 @@ Query.prototype._completeOne = function(doc, res, projection, callback) {
2635
2631
 
2636
2632
  if (!mongooseOptions.populate) {
2637
2633
  const versionKey = this.schema.options.versionKey;
2638
- if (mongooseOptions.lean && mongooseOptions.lean.versionKey === false && versionKey) {
2634
+ if (mongooseOptions.lean?.versionKey === false && versionKey) {
2639
2635
  if (versionKey in doc) {
2640
2636
  delete doc[versionKey];
2641
2637
  }
@@ -2712,8 +2708,10 @@ Query.prototype._findOne = async function _findOne() {
2712
2708
  throw err;
2713
2709
  }
2714
2710
 
2715
- applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
2716
- applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
2711
+ const dbOptions = this.model.db.options;
2712
+ const baseOptions = this.model.base.options;
2713
+ applyGlobalMaxTimeMS(this.options, dbOptions, baseOptions);
2714
+ applyGlobalDiskUse(this.options, dbOptions, baseOptions);
2717
2715
 
2718
2716
  const options = this._optionsForExec();
2719
2717
 
@@ -2808,8 +2806,10 @@ Query.prototype._countDocuments = async function _countDocuments() {
2808
2806
  throw this.error();
2809
2807
  }
2810
2808
 
2811
- applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
2812
- applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
2809
+ const dbOptions = this.model.db.options;
2810
+ const baseOptions = this.model.base.options;
2811
+ applyGlobalMaxTimeMS(this.options, dbOptions, baseOptions);
2812
+ applyGlobalDiskUse(this.options, dbOptions, baseOptions);
2813
2813
 
2814
2814
  const options = this._optionsForExec();
2815
2815
 
@@ -2836,7 +2836,7 @@ Query.prototype._applyTranslateAliases = function _applyTranslateAliases() {
2836
2836
  return;
2837
2837
  }
2838
2838
 
2839
- if (this.model?.schema?.aliases && Object.keys(this.model.schema.aliases).length > 0) {
2839
+ if (this.model?.schema?.aliases && utils.hasOwnKeys(this.model.schema.aliases)) {
2840
2840
  this.model.translateAliases(this._conditions, true);
2841
2841
  this.model.translateAliases(this._fields, true);
2842
2842
  this.model.translateAliases(this._update, true);
@@ -2974,8 +2974,10 @@ Query.prototype.__distinct = async function __distinct() {
2974
2974
  throw this.error();
2975
2975
  }
2976
2976
 
2977
- applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
2978
- applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
2977
+ const dbOptions = this.model.db.options;
2978
+ const baseOptions = this.model.base.options;
2979
+ applyGlobalMaxTimeMS(this.options, dbOptions, baseOptions);
2980
+ applyGlobalDiskUse(this.options, dbOptions, baseOptions);
2979
2981
 
2980
2982
  const options = this._optionsForExec();
2981
2983
 
@@ -3075,7 +3077,7 @@ Query.prototype.sort = function(arg, options) {
3075
3077
  if (this.options.sort == null) {
3076
3078
  this.options.sort = {};
3077
3079
  }
3078
- if (options && options.override) {
3080
+ if (options?.override) {
3079
3081
  this.options.sort = {};
3080
3082
  }
3081
3083
  const sort = this.options.sort;
@@ -3345,13 +3347,13 @@ function completeOne(model, doc, res, options, fields, userProvidedFields, pop,
3345
3347
  */
3346
3348
 
3347
3349
  function prepareDiscriminatorCriteria(query) {
3348
- if (!query || !query.model || !query.model.schema) {
3350
+ if (!query?.model?.schema) {
3349
3351
  return;
3350
3352
  }
3351
3353
 
3352
3354
  const schema = query.model.schema;
3353
3355
 
3354
- if (schema && schema.discriminatorMapping && !schema.discriminatorMapping.isRoot) {
3356
+ if (schema?.discriminatorMapping && !schema.discriminatorMapping.isRoot) {
3355
3357
  query._conditions[schema.discriminatorMapping.key] = schema.discriminatorMapping.value;
3356
3358
  }
3357
3359
  }
@@ -3492,8 +3494,10 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
3492
3494
  throw this.error();
3493
3495
  }
3494
3496
 
3495
- applyGlobalMaxTimeMS(this.options, this.model.db.options, this.model.base.options);
3496
- applyGlobalDiskUse(this.options, this.model.db.options, this.model.base.options);
3497
+ const dbOptions = this.model.db.options;
3498
+ const baseOptions = this.model.base.options;
3499
+ applyGlobalMaxTimeMS(this.options, dbOptions, baseOptions);
3500
+ applyGlobalDiskUse(this.options, dbOptions, baseOptions);
3497
3501
 
3498
3502
  if ('strict' in this.options) {
3499
3503
  this._mongooseOptions.strict = this.options.strict;
@@ -3509,7 +3513,7 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
3509
3513
  this._update = setDefaultsOnInsert(this._conditions, this.model.schema,
3510
3514
  this._update, _opts);
3511
3515
 
3512
- if (!this._update || Object.keys(this._update).length === 0) {
3516
+ if (!this._update || utils.hasOwnKeys(this._update) === false) {
3513
3517
  if (options.upsert) {
3514
3518
  // still need to do the upsert to empty doc
3515
3519
  const $set = clone(this._update);
@@ -3526,7 +3530,7 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() {
3526
3530
  // In order to make MongoDB 2.6 happy (see
3527
3531
  // https://jira.mongodb.org/browse/SERVER-12266 and related issues)
3528
3532
  // if we have an actual update document but $set is empty, junk the $set.
3529
- if (this._update.$set && Object.keys(this._update.$set).length === 0) {
3533
+ if (this._update.$set && utils.hasOwnKeys(this._update.$set) === false) {
3530
3534
  delete this._update.$set;
3531
3535
  }
3532
3536
  }
@@ -4015,7 +4019,7 @@ Query.prototype._mergeUpdate = function(update) {
4015
4019
  this._update = Array.isArray(update) ? [] : {};
4016
4020
  }
4017
4021
 
4018
- if (update == null || (typeof update === 'object' && Object.keys(update).length === 0)) {
4022
+ if (update == null || (typeof update === 'object' && utils.hasOwnKeys(update) === false)) {
4019
4023
  return;
4020
4024
  }
4021
4025
 
@@ -4067,7 +4071,7 @@ async function _updateThunk(op) {
4067
4071
  } else {
4068
4072
  this._update = this._castUpdate(this._update);
4069
4073
 
4070
- if (this._update == null || Object.keys(this._update).length === 0) {
4074
+ if (this._update == null || utils.hasOwnKeys(this._update) === false) {
4071
4075
  return { acknowledged: false };
4072
4076
  }
4073
4077
 
@@ -4406,7 +4410,7 @@ function _update(query, op, filter, doc, options, callback) {
4406
4410
  }
4407
4411
 
4408
4412
  const updatePipeline = query?.model?.base?.options?.updatePipeline;
4409
- if (updatePipeline != null && (options == null || options.updatePipeline == null)) {
4413
+ if (updatePipeline != null && options?.updatePipeline == null) {
4410
4414
  options = options || {};
4411
4415
  options.updatePipeline = updatePipeline;
4412
4416
  }
@@ -4501,7 +4505,7 @@ Query.prototype.orFail = function(err) {
4501
4505
  case 'replaceOne':
4502
4506
  case 'updateMany':
4503
4507
  case 'updateOne':
4504
- if (res && res.matchedCount === 0) {
4508
+ if (res?.matchedCount === 0) {
4505
4509
  throw _orFailError(err, this);
4506
4510
  }
4507
4511
  break;
@@ -4595,7 +4599,7 @@ Query.prototype.exec = async function exec(op) {
4595
4599
  throw new MongooseError('Query has invalid `op`: "' + this.op + '"');
4596
4600
  }
4597
4601
 
4598
- if (this.options && this.options.sort && typeof this.options.sort === 'object' && Object.hasOwn(this.options.sort, '')) {
4602
+ if (this.options?.sort && typeof this.options.sort === 'object' && Object.hasOwn(this.options.sort, '')) {
4599
4603
  throw new Error('Invalid field "" passed to sort()');
4600
4604
  }
4601
4605
 
@@ -4810,7 +4814,7 @@ Query.prototype._castUpdate = function _castUpdate(obj) {
4810
4814
  let schema = this.schema;
4811
4815
 
4812
4816
  const discriminatorKey = schema.options.discriminatorKey;
4813
- const baseSchema = schema._baseSchema ? schema._baseSchema : schema;
4817
+ const baseSchema = schema._baseSchema || schema;
4814
4818
  if (this._mongooseOptions.overwriteDiscriminatorKey &&
4815
4819
  obj[discriminatorKey] != null &&
4816
4820
  baseSchema.discriminators) {
@@ -4888,8 +4892,7 @@ Query.prototype._castUpdate = function _castUpdate(obj) {
4888
4892
  * @api public
4889
4893
  */
4890
4894
 
4891
- Query.prototype.populate = function() {
4892
- const args = Array.from(arguments);
4895
+ Query.prototype.populate = function(...args) {
4893
4896
  // Bail when given no truthy arguments
4894
4897
  if (!args.some(Boolean)) {
4895
4898
  return this;
@@ -4902,7 +4905,7 @@ Query.prototype.populate = function() {
4902
4905
  if (opts.lean != null) {
4903
4906
  const lean = opts.lean;
4904
4907
  for (const populateOptions of res) {
4905
- if ((populateOptions && populateOptions.options && populateOptions.options.lean) == null) {
4908
+ if (populateOptions?.options?.lean == null) {
4906
4909
  populateOptions.options = populateOptions.options || {};
4907
4910
  populateOptions.options.lean = lean;
4908
4911
  }
@@ -4917,7 +4920,7 @@ Query.prototype.populate = function() {
4917
4920
 
4918
4921
  for (const populateOptions of res) {
4919
4922
  const path = populateOptions.path;
4920
- if (pop[path] && pop[path].populate && populateOptions.populate) {
4923
+ if (pop[path]?.populate && populateOptions.populate) {
4921
4924
  populateOptions.populate = pop[path].populate.concat(populateOptions.populate);
4922
4925
  }
4923
4926
 
@@ -4999,7 +5002,7 @@ Query.prototype.cast = function(model, obj) {
4999
5002
  model = getDiscriminatorByValue(model.discriminators, obj[discriminatorKey]) || model;
5000
5003
  }
5001
5004
 
5002
- const opts = { upsert: this.options && this.options.upsert };
5005
+ const opts = { upsert: this.options?.upsert };
5003
5006
  if (this.options) {
5004
5007
  if ('strict' in this.options) {
5005
5008
  opts.strict = this.options.strict;
@@ -5197,7 +5200,7 @@ Query.prototype.cursor = function cursor(opts) {
5197
5200
  Query.prototype.tailable = function(val, opts) {
5198
5201
  // we need to support the tailable({ awaitData : true }) as well as the
5199
5202
  // tailable(true, {awaitData :true}) syntax that mquery does not support
5200
- if (val != null && typeof val.constructor === 'function' && val.constructor.name === 'Object') {
5203
+ if (typeof val?.constructor === 'function' && val.constructor.name === 'Object') {
5201
5204
  opts = val;
5202
5205
  val = true;
5203
5206
  }
@@ -5559,11 +5562,11 @@ Query.prototype.center = Query.base.circle;
5559
5562
  */
5560
5563
 
5561
5564
  Query.prototype.centerSphere = function() {
5562
- if (arguments[0] != null && typeof arguments[0].constructor === 'function' && arguments[0].constructor.name === 'Object') {
5565
+ if (typeof arguments[0]?.constructor === 'function' && arguments[0].constructor.name === 'Object') {
5563
5566
  arguments[0].spherical = true;
5564
5567
  }
5565
5568
 
5566
- if (arguments[1] != null && typeof arguments[1].constructor === 'function' && arguments[1].constructor.name === 'Object') {
5569
+ if (typeof arguments[1]?.constructor === 'function' && arguments[1].constructor.name === 'Object') {
5567
5570
  arguments[1].spherical = true;
5568
5571
  }
5569
5572
 
@@ -30,11 +30,11 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query,
30
30
  // lean options should trickle through all queries
31
31
  if (options.lean != null) {
32
32
  pop
33
- .filter(p => (p && p.options && p.options.lean) == null)
33
+ .filter(p => p?.options?.lean == null)
34
34
  .forEach(makeLean(options.lean));
35
35
  }
36
36
 
37
- const session = query && query.options && query.options.session || null;
37
+ const session = query?.options?.session || null;
38
38
  if (session != null) {
39
39
  pop.forEach(path => {
40
40
  if (path.options == null) {
@@ -80,7 +80,7 @@ exports.createModel = function createModel(model, doc, fields, userProvidedField
80
80
  model.schema.discriminatorMapping :
81
81
  null;
82
82
 
83
- const key = discriminatorMapping && discriminatorMapping.isRoot ?
83
+ const key = discriminatorMapping?.isRoot ?
84
84
  discriminatorMapping.key :
85
85
  null;
86
86
 
@@ -179,10 +179,10 @@ exports.applyPaths = function applyPaths(fields, schema, sanitizeProjection) {
179
179
  // inclusive, minus path is treated as equivalent to `key: 0`.
180
180
  // But we also allow using `-name` to remove `name` from an inclusive
181
181
  // projection if `name` has schema-level `select: true`.
182
- if ((!type || !type.selected) || exclude !== false) {
182
+ if (!type?.selected || exclude !== false) {
183
183
  fields[path] = 0;
184
184
  exclude = true;
185
- } else if (type && type.selected && exclude === false) {
185
+ } else if (type?.selected && exclude === false) {
186
186
  // Make a note of minus paths that are overwriting paths that are
187
187
  // included by default.
188
188
  minusPathsToSkip.add(path);
@@ -204,10 +204,7 @@ exports.applyPaths = function applyPaths(fields, schema, sanitizeProjection) {
204
204
  }
205
205
  break;
206
206
  case false:
207
- if (schema &&
208
- schema.paths['_id'] &&
209
- schema.paths['_id'].options &&
210
- schema.paths['_id'].options.select === false) {
207
+ if (schema?.paths['_id']?.options?.select === false) {
211
208
  fields._id = 0;
212
209
  }
213
210
 
@@ -260,7 +257,7 @@ exports.applyPaths = function applyPaths(fields, schema, sanitizeProjection) {
260
257
  if (type.$isSchemaMap || path.endsWith('.$*')) {
261
258
  const plusPath = '+' + path;
262
259
  const hasPlusPath = fields && plusPath in fields;
263
- if (type.options && type.options.select === false && !hasPlusPath) {
260
+ if (type.options?.select === false && !hasPlusPath) {
264
261
  excluded.push(path);
265
262
  }
266
263
  return;
@@ -352,7 +349,7 @@ exports.applyPaths = function applyPaths(fields, schema, sanitizeProjection) {
352
349
  // Special case: if user has included a parent path of a discriminator key,
353
350
  // don't explicitly project in the discriminator key because that will
354
351
  // project out everything else under the parent path
355
- if (!exclude && (type && type.options && type.options.$skipDiscriminatorCheck || false)) {
352
+ if (!exclude && (type?.options?.$skipDiscriminatorCheck || false)) {
356
353
  let cur = '';
357
354
  for (let i = 0; i < pieces.length; ++i) {
358
355
  cur += (cur.length === 0 ? '' : '.') + pieces[i];
@@ -378,7 +375,7 @@ function makeLean(val) {
378
375
  return function(option) {
379
376
  option.options || (option.options = {});
380
377
 
381
- if (val != null && Array.isArray(val.virtuals)) {
378
+ if (Array.isArray(val?.virtuals)) {
382
379
  val = Object.assign({}, val);
383
380
  val.virtuals = val.virtuals.
384
381
  filter(path => typeof path === 'string' && path.startsWith(option.path + '.')).
@@ -47,7 +47,7 @@ function SchemaArray(key, cast, options, schemaOptions, parentSchema) {
47
47
  EmbeddedDoc || (EmbeddedDoc = require('../types').Embedded);
48
48
 
49
49
  let typeKey = 'type';
50
- if (schemaOptions && schemaOptions.typeKey) {
50
+ if (schemaOptions?.typeKey) {
51
51
  typeKey = schemaOptions.typeKey;
52
52
  }
53
53
  this.schemaOptions = schemaOptions;
@@ -66,7 +66,7 @@ function SchemaArray(key, cast, options, schemaOptions, parentSchema) {
66
66
  }
67
67
  }
68
68
 
69
- if (options != null && options.ref != null && castOptions.ref == null) {
69
+ if (options?.ref != null && castOptions.ref == null) {
70
70
  castOptions.ref = options.ref;
71
71
  }
72
72
 
@@ -255,9 +255,7 @@ SchemaArray.prototype.checkRequired = function checkRequired(value, doc) {
255
255
  SchemaArray.prototype.enum = function() {
256
256
  let arr = this;
257
257
  while (true) {
258
- const instance = arr &&
259
- arr.embeddedSchemaType &&
260
- arr.embeddedSchemaType.instance;
258
+ const instance = arr?.embeddedSchemaType?.instance;
261
259
  if (instance === 'Array') {
262
260
  arr = arr.embeddedSchemaType;
263
261
  continue;
@@ -287,7 +285,7 @@ SchemaArray.prototype.enum = function() {
287
285
  */
288
286
 
289
287
  SchemaArray.prototype.applyGetters = function(value, scope) {
290
- if (scope != null && scope.$__ != null && scope.$populated(this.path)) {
288
+ if (scope?.$__ != null && scope.$populated(this.path)) {
291
289
  // means the object id was populated
292
290
  return value;
293
291
  }
@@ -376,7 +374,7 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
376
374
  value = MongooseArray(rawValue, path, doc, this);
377
375
  rawValue = value.__array;
378
376
 
379
- if (init && doc != null && doc.$__ != null && doc.$populated(this.path)) {
377
+ if (init && doc?.$__ != null && doc.$populated(this.path)) {
380
378
  return value;
381
379
  }
382
380
 
@@ -411,11 +409,11 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
411
409
  return value;
412
410
  }
413
411
 
414
- const castNonArraysOption = this.options.castNonArrays != null ? this.options.castNonArrays : SchemaArray.options.castNonArrays;
412
+ const castNonArraysOption = this.options.castNonArrays ?? SchemaArray.options.castNonArrays;
415
413
  if (init || castNonArraysOption) {
416
414
  // gh-2442: if we're loading this from the db and its not an array, mark
417
415
  // the whole array as modified.
418
- if (!!doc && !!init) {
416
+ if (doc && init) {
419
417
  doc.markModified(this.path);
420
418
  }
421
419
  return this.cast([value], doc, init);
@@ -586,12 +584,12 @@ function cast$all(val, context) {
586
584
  return v;
587
585
  }
588
586
  if (v.$elemMatch != null) {
589
- return { $elemMatch: cast(this.embeddedSchemaType.schema, v.$elemMatch, null, this && this.$$context) };
587
+ return { $elemMatch: cast(this.embeddedSchemaType.schema, v.$elemMatch, null, this?.$$context) };
590
588
  }
591
589
 
592
590
  const o = {};
593
591
  o[this.path] = v;
594
- return cast(this.embeddedSchemaType.schema, o, null, this && this.$$context)[this.path];
592
+ return cast(this.embeddedSchemaType.schema, o, null, this?.$$context)[this.path];
595
593
  }, this);
596
594
 
597
595
  return this.castForQuery(null, val, context);
@@ -639,7 +637,7 @@ function createLogicalQueryOperatorHandler(op) {
639
637
 
640
638
  const ret = [];
641
639
  for (const obj of val) {
642
- ret.push(cast(this.embeddedSchemaType.schema ?? context.schema, obj, null, this && this.$$context));
640
+ ret.push(cast(this.embeddedSchemaType.schema ?? context.schema, obj, null, this?.$$context));
643
641
  }
644
642
 
645
643
  return ret;
@@ -50,7 +50,7 @@ SchemaBuffer.prototype.OptionsConstructor = SchemaBufferOptions;
50
50
  * ignore
51
51
  */
52
52
 
53
- SchemaBuffer._checkRequired = v => !!(v && v.length);
53
+ SchemaBuffer._checkRequired = v => !!v?.length;
54
54
 
55
55
  /**
56
56
  * Sets a default option for all Buffer instances.
@@ -146,12 +146,12 @@ SchemaBuffer.prototype.checkRequired = function(value, doc) {
146
146
  SchemaBuffer.prototype.cast = function(value, doc, init, prev, options) {
147
147
  let ret;
148
148
  if (SchemaType._isRef(this, value, doc, init)) {
149
- if (value && value.isMongooseBuffer) {
149
+ if (value?.isMongooseBuffer) {
150
150
  return value;
151
151
  }
152
152
 
153
153
  if (Buffer.isBuffer(value)) {
154
- if (!value || !value.isMongooseBuffer) {
154
+ if (!value?.isMongooseBuffer) {
155
155
  value = new MongooseBuffer(value, [this.path, doc]);
156
156
  if (this.options.subtype != null) {
157
157
  value._subtype = this.options.subtype;
@@ -175,16 +175,16 @@ SchemaBuffer.prototype.cast = function(value, doc, init, prev, options) {
175
175
  }
176
176
 
177
177
  // documents
178
- if (value && value._id) {
178
+ if (value?._id) {
179
179
  value = value._id;
180
180
  }
181
181
 
182
- if (value && value.isMongooseBuffer) {
182
+ if (value?.isMongooseBuffer) {
183
183
  return value;
184
184
  }
185
185
 
186
186
  if (Buffer.isBuffer(value)) {
187
- if (!value || !value.isMongooseBuffer) {
187
+ if (!value?.isMongooseBuffer) {
188
188
  value = new MongooseBuffer(value, [this.path, doc]);
189
189
  if (this.options.subtype != null) {
190
190
  value._subtype = this.options.subtype;
@@ -41,19 +41,18 @@ let Subdocument;
41
41
  */
42
42
 
43
43
  function SchemaDocumentArray(key, schema, options, schemaOptions, parentSchema) {
44
- if (schema.options && schema.options.timeseries) {
44
+ if (schema.options?.timeseries) {
45
45
  throw new InvalidSchemaOptionError(key, 'timeseries');
46
46
  }
47
- const schemaTypeIdOption = SchemaDocumentArray.defaultOptions &&
48
- SchemaDocumentArray.defaultOptions._id;
47
+ const schemaTypeIdOption = SchemaDocumentArray.defaultOptions?._id;
49
48
  if (schemaTypeIdOption != null) {
50
49
  schemaOptions = schemaOptions || {};
51
50
  schemaOptions._id = schemaTypeIdOption;
52
51
  }
53
52
 
54
- if (schemaOptions != null && schemaOptions._id != null) {
53
+ if (schemaOptions?._id != null) {
55
54
  schema = handleIdOption(schema, schemaOptions);
56
- } else if (options != null && options._id != null) {
55
+ } else if (options?._id != null) {
57
56
  schema = handleIdOption(schema, options);
58
57
  }
59
58
 
@@ -150,7 +149,7 @@ function _createConstructor(schema, options, baseClass) {
150
149
 
151
150
  schema._preCompile();
152
151
 
153
- const proto = baseClass != null ? baseClass.prototype : Subdocument.prototype;
152
+ const proto = baseClass?.prototype ?? Subdocument.prototype;
154
153
  EmbeddedDocument.prototype = Object.create(proto);
155
154
  EmbeddedDocument.prototype.$__setSchema(schema);
156
155
  EmbeddedDocument.schema = schema;
@@ -260,7 +259,7 @@ SchemaDocumentArray.prototype.doValidate = async function doValidate(array, scop
260
259
  doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
261
260
  }
262
261
 
263
- if (options != null && options.validateModifiedOnly && !doc.$isModified()) {
262
+ if (options?.validateModifiedOnly && !doc.$isModified()) {
264
263
  continue;
265
264
  }
266
265
 
@@ -287,7 +286,7 @@ SchemaDocumentArray.prototype.doValidateSync = function(array, scope, options) {
287
286
  return schemaTypeError;
288
287
  }
289
288
 
290
- const count = array && array.length;
289
+ const count = array?.length;
291
290
  let resultError = null;
292
291
 
293
292
  if (!count) {
@@ -312,7 +311,7 @@ SchemaDocumentArray.prototype.doValidateSync = function(array, scope, options) {
312
311
  doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
313
312
  }
314
313
 
315
- if (options != null && options.validateModifiedOnly && !doc.$isModified()) {
314
+ if (options?.validateModifiedOnly && !doc.$isModified()) {
316
315
  continue;
317
316
  }
318
317
 
@@ -339,7 +338,7 @@ SchemaDocumentArray.prototype.getDefault = function(scope, init, options) {
339
338
  return ret;
340
339
  }
341
340
 
342
- if (options && options.skipCast) {
341
+ if (options?.skipCast) {
343
342
  return ret;
344
343
  }
345
344
 
@@ -386,7 +385,7 @@ SchemaDocumentArray.prototype.cast = function(value, doc, init, prev, options) {
386
385
  MongooseDocumentArray || (MongooseDocumentArray = require('../types/documentArray'));
387
386
 
388
387
  // Skip casting if `value` is the same as the previous value, no need to cast. See gh-9266
389
- if (value != null && value[arrayPathSymbol] != null && value === prev) {
388
+ if (value?.[arrayPathSymbol] != null && value === prev) {
390
389
  return value;
391
390
  }
392
391
 
@@ -463,7 +462,7 @@ SchemaDocumentArray.prototype.cast = function(value, doc, init, prev, options) {
463
462
  subdoc = new Constructor(null, value, initDocumentOptions, selected, i);
464
463
  rawArray[i] = subdoc.$init(rawArray[i], options);
465
464
  } else {
466
- if (prev && typeof prev.id === 'function') {
465
+ if (typeof prev?.id === 'function') {
467
466
  subdoc = prev.id(rawArray[i]._id);
468
467
  }
469
468
 
@@ -621,23 +620,16 @@ function cast$elemMatch(val, context) {
621
620
 
622
621
  // Is this an embedded discriminator and is the discriminator key set?
623
622
  // If so, use the discriminator schema. See gh-7449
624
- const discriminatorKey = this &&
625
- this.Constructor &&
626
- this.Constructor.schema &&
627
- this.Constructor.schema.options &&
628
- this.Constructor.schema.options.discriminatorKey;
629
- const discriminators = this &&
630
- this.Constructor &&
631
- this.Constructor.schema &&
632
- this.Constructor.schema.discriminators || {};
623
+ const discriminatorKey = this?.Constructor?.schema?.options?.discriminatorKey;
624
+ const discriminators = this?.Constructor?.schema?.discriminators || {};
633
625
  if (discriminatorKey != null &&
634
626
  val[discriminatorKey] != null &&
635
627
  discriminators[val[discriminatorKey]] != null) {
636
- return cast(discriminators[val[discriminatorKey]], val, null, this && this.$$context);
628
+ return cast(discriminators[val[discriminatorKey]], val, null, this?.$$context);
637
629
  }
638
630
 
639
631
  const schema = this.Constructor.schema ?? context.schema;
640
- return cast(schema, val, null, this && this.$$context);
632
+ return cast(schema, val, null, this?.$$context);
641
633
  }
642
634
 
643
635
  /**