mongoose 8.20.1 → 8.20.3

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 (38) hide show
  1. package/dist/browser.umd.js +1 -1
  2. package/lib/aggregate.js +1 -1
  3. package/lib/cast.js +1 -1
  4. package/lib/connection.js +9 -9
  5. package/lib/document.js +58 -17
  6. package/lib/drivers/node-mongodb-native/connection.js +2 -2
  7. package/lib/error/objectParameter.js +1 -1
  8. package/lib/helpers/common.js +1 -1
  9. package/lib/helpers/indexes/applySchemaCollation.js +1 -1
  10. package/lib/helpers/indexes/isDefaultIdIndex.js +1 -1
  11. package/lib/helpers/model/applyMethods.js +1 -1
  12. package/lib/helpers/model/castBulkWrite.js +13 -6
  13. package/lib/helpers/populate/getModelsMapForPopulate.js +3 -3
  14. package/lib/helpers/populate/modelNamesFromRefPath.js +1 -1
  15. package/lib/helpers/populate/removeDeselectedForeignField.js +1 -1
  16. package/lib/helpers/projection/applyProjection.js +2 -2
  17. package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +1 -1
  18. package/lib/helpers/setDefaultsOnInsert.js +2 -2
  19. package/lib/helpers/timestamps/setupTimestamps.js +1 -1
  20. package/lib/helpers/update/applyTimestampsToUpdate.js +38 -25
  21. package/lib/helpers/update/decorateUpdateWithVersionKey.js +1 -1
  22. package/lib/model.js +12 -15
  23. package/lib/mongoose.js +3 -4
  24. package/lib/query.js +3 -3
  25. package/lib/schema/array.js +1 -1
  26. package/lib/schema.js +21 -21
  27. package/lib/schemaType.js +8 -8
  28. package/lib/types/array/index.js +5 -5
  29. package/lib/types/documentArray/index.js +6 -6
  30. package/lib/types/objectid.js +1 -1
  31. package/lib/utils.js +1 -15
  32. package/lib/virtualType.js +1 -1
  33. package/package.json +3 -1
  34. package/types/index.d.ts +1 -1
  35. package/types/inferrawdoctype.d.ts +1 -1
  36. package/types/inferschematype.d.ts +16 -23
  37. package/types/models.d.ts +38 -85
  38. package/types/virtuals.d.ts +3 -3
package/lib/aggregate.js CHANGED
@@ -103,7 +103,7 @@ Aggregate.prototype._optionsForExec = function() {
103
103
  const options = this.options || {};
104
104
 
105
105
  const asyncLocalStorage = this.model()?.db?.base.transactionAsyncLocalStorage?.getStore();
106
- if (!options.hasOwnProperty('session') && asyncLocalStorage?.session != null) {
106
+ if (!Object.hasOwn(options, 'session') && asyncLocalStorage?.session != null) {
107
107
  options.session = asyncLocalStorage.session;
108
108
  }
109
109
 
package/lib/cast.js CHANGED
@@ -107,7 +107,7 @@ module.exports = function cast(schema, obj, options, context) {
107
107
  val = cast(schema, val, options, context);
108
108
  } else if (path === '$text') {
109
109
  val = castTextSearch(val, path);
110
- } else if (path === '$comment' && !schema.paths.hasOwnProperty('$comment')) {
110
+ } else if (path === '$comment' && !Object.hasOwn(schema.paths, '$comment')) {
111
111
  val = castString(val, path);
112
112
  obj[path] = val;
113
113
  } else {
package/lib/connection.js CHANGED
@@ -164,7 +164,7 @@ Object.defineProperty(Connection.prototype, 'readyState', {
164
164
  */
165
165
 
166
166
  Connection.prototype.get = function getOption(key) {
167
- if (this.config.hasOwnProperty(key)) {
167
+ if (Object.hasOwn(this.config, key)) {
168
168
  return this.config[key];
169
169
  }
170
170
 
@@ -192,7 +192,7 @@ Connection.prototype.get = function getOption(key) {
192
192
  */
193
193
 
194
194
  Connection.prototype.set = function setOption(key, val) {
195
- if (this.config.hasOwnProperty(key)) {
195
+ if (Object.hasOwn(this.config, key)) {
196
196
  this.config[key] = val;
197
197
  return val;
198
198
  }
@@ -459,7 +459,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
459
459
 
460
460
  const ordered = options.ordered == null ? true : options.ordered;
461
461
  const asyncLocalStorage = this.base.transactionAsyncLocalStorage?.getStore();
462
- if ((!options || !options.hasOwnProperty('session')) && asyncLocalStorage?.session != null) {
462
+ if ((!options || !Object.hasOwn(options, 'session')) && asyncLocalStorage?.session != null) {
463
463
  options = { ...options, session: asyncLocalStorage.session };
464
464
  }
465
465
 
@@ -477,7 +477,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
477
477
  if (op.name == null) {
478
478
  throw new MongooseError('Must specify operation name in Connection.prototype.bulkWrite()');
479
479
  }
480
- if (!castBulkWrite.cast.hasOwnProperty(op.name)) {
480
+ if (!Object.hasOwn(castBulkWrite.cast, op.name)) {
481
481
  throw new MongooseError(`Unrecognized bulkWrite() operation name ${op.name}`);
482
482
  }
483
483
 
@@ -513,7 +513,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
513
513
  results[i] = error;
514
514
  continue;
515
515
  }
516
- if (!castBulkWrite.cast.hasOwnProperty(op.name)) {
516
+ if (!Object.hasOwn(castBulkWrite.cast, op.name)) {
517
517
  const error = new MongooseError(`Unrecognized bulkWrite() operation name ${op.name}`);
518
518
  validationErrors.push({ index: i, error: error });
519
519
  results[i] = error;
@@ -772,10 +772,10 @@ async function _wrapUserTransaction(fn, session, mongoose) {
772
772
  function _resetSessionDocuments(session) {
773
773
  for (const doc of session[sessionNewDocuments].keys()) {
774
774
  const state = session[sessionNewDocuments].get(doc);
775
- if (state.hasOwnProperty('isNew')) {
775
+ if (Object.hasOwn(state, 'isNew')) {
776
776
  doc.$isNew = state.isNew;
777
777
  }
778
- if (state.hasOwnProperty('versionKey')) {
778
+ if (Object.hasOwn(state, 'versionKey')) {
779
779
  doc.set(doc.schema.options.versionKey, state.versionKey);
780
780
  }
781
781
 
@@ -1013,7 +1013,7 @@ Connection.prototype.onOpen = function() {
1013
1013
  // avoid having the collection subscribe to our event emitter
1014
1014
  // to prevent 0.3 warning
1015
1015
  for (const i in this.collections) {
1016
- if (utils.object.hasOwnProperty(this.collections, i)) {
1016
+ if (Object.hasOwn(this.collections, i)) {
1017
1017
  this.collections[i].onOpen();
1018
1018
  }
1019
1019
  }
@@ -1321,7 +1321,7 @@ Connection.prototype.onClose = function onClose(force) {
1321
1321
  // avoid having the collection subscribe to our event emitter
1322
1322
  // to prevent 0.3 warning
1323
1323
  for (const i in this.collections) {
1324
- if (utils.object.hasOwnProperty(this.collections, i)) {
1324
+ if (Object.hasOwn(this.collections, i)) {
1325
1325
  this.collections[i].onClose(force);
1326
1326
  }
1327
1327
  }
package/lib/document.js CHANGED
@@ -648,6 +648,10 @@ Document.prototype.init = function(doc, opts, fn) {
648
648
  opts = null;
649
649
  }
650
650
 
651
+ if (doc == null) {
652
+ throw new ObjectParameterError(doc, 'doc', 'init');
653
+ }
654
+
651
655
  this.$__init(doc, opts);
652
656
 
653
657
  if (fn) {
@@ -780,7 +784,7 @@ function init(self, obj, doc, opts, prefix) {
780
784
  }
781
785
  } else {
782
786
  // Retain order when overwriting defaults
783
- if (doc.hasOwnProperty(i) && value !== void 0 && !opts.hydratedPopulatedDocs) {
787
+ if (Object.hasOwn(doc, i) && value !== void 0 && !opts.hydratedPopulatedDocs) {
784
788
  delete doc[i];
785
789
  }
786
790
  if (value === null) {
@@ -1156,7 +1160,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1156
1160
  const orderedKeys = Object.keys(this.$__schema.tree);
1157
1161
  for (let i = 0, len = orderedKeys.length; i < len; ++i) {
1158
1162
  (key = orderedKeys[i]) &&
1159
- (this._doc.hasOwnProperty(key)) &&
1163
+ (Object.hasOwn(this._doc, key)) &&
1160
1164
  (orderedDoc[key] = undefined);
1161
1165
  }
1162
1166
  this._doc = Object.assign(orderedDoc, this._doc);
@@ -1206,8 +1210,8 @@ Document.prototype.$set = function $set(path, val, type, options) {
1206
1210
  return this;
1207
1211
  }
1208
1212
  const wasModified = this.$isModified(path);
1209
- const hasInitialVal = this.$__.savedState != null && this.$__.savedState.hasOwnProperty(path);
1210
- if (this.$__.savedState != null && !this.$isNew && !this.$__.savedState.hasOwnProperty(path)) {
1213
+ const hasInitialVal = this.$__.savedState != null && Object.hasOwn(this.$__.savedState, path);
1214
+ if (this.$__.savedState != null && !this.$isNew && !Object.hasOwn(this.$__.savedState, path)) {
1211
1215
  const initialVal = this.$__getValue(path);
1212
1216
  this.$__.savedState[path] = initialVal;
1213
1217
 
@@ -1512,7 +1516,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1512
1516
  this.$__.session[sessionNewDocuments].get(this).modifiedPaths &&
1513
1517
  !this.$__.session[sessionNewDocuments].get(this).modifiedPaths.has(savedStatePath);
1514
1518
  if (savedState != null &&
1515
- savedState.hasOwnProperty(savedStatePath) &&
1519
+ Object.hasOwn(savedState, savedStatePath) &&
1516
1520
  (!isInTransaction || isModifiedWithinTransaction) &&
1517
1521
  utils.deepEqual(val, savedState[savedStatePath])) {
1518
1522
  this.unmarkModified(path);
@@ -1994,7 +1998,7 @@ Document.prototype.$get = Document.prototype.get;
1994
1998
 
1995
1999
  Document.prototype.$__path = function(path) {
1996
2000
  const adhocs = this.$__.adhocPaths;
1997
- const adhocType = adhocs && adhocs.hasOwnProperty(path) ? adhocs[path] : null;
2001
+ const adhocType = adhocs && Object.hasOwn(adhocs, path) ? adhocs[path] : null;
1998
2002
 
1999
2003
  if (adhocType) {
2000
2004
  return adhocType;
@@ -2038,7 +2042,7 @@ Document.prototype.$__saveInitialState = function $__saveInitialState(path) {
2038
2042
  if (savedState != null) {
2039
2043
  const firstDot = savedStatePath.indexOf('.');
2040
2044
  const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
2041
- if (!savedState.hasOwnProperty(topLevelPath)) {
2045
+ if (!Object.hasOwn(savedState, topLevelPath)) {
2042
2046
  savedState[topLevelPath] = clone(this.$__getValue(topLevelPath));
2043
2047
  }
2044
2048
  }
@@ -2349,7 +2353,7 @@ Document.prototype.$isDefault = function(path) {
2349
2353
  }
2350
2354
 
2351
2355
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2352
- return this.$__.activePaths.getStatePaths('default').hasOwnProperty(path);
2356
+ return Object.hasOwn(this.$__.activePaths.getStatePaths('default'), path);
2353
2357
  }
2354
2358
 
2355
2359
  let paths = path;
@@ -2357,7 +2361,7 @@ Document.prototype.$isDefault = function(path) {
2357
2361
  paths = paths.split(' ');
2358
2362
  }
2359
2363
 
2360
- return paths.some(path => this.$__.activePaths.getStatePaths('default').hasOwnProperty(path));
2364
+ return paths.some(path => Object.hasOwn(this.$__.activePaths.getStatePaths('default'), path));
2361
2365
  };
2362
2366
 
2363
2367
  /**
@@ -2411,7 +2415,7 @@ Document.prototype.isDirectModified = function(path) {
2411
2415
  }
2412
2416
 
2413
2417
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2414
- const res = this.$__.activePaths.getStatePaths('modify').hasOwnProperty(path);
2418
+ const res = Object.hasOwn(this.$__.activePaths.getStatePaths('modify'), path);
2415
2419
  if (res || path.indexOf('.') === -1) {
2416
2420
  return res;
2417
2421
  }
@@ -2450,7 +2454,7 @@ Document.prototype.isInit = function(path) {
2450
2454
  }
2451
2455
 
2452
2456
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2453
- return this.$__.activePaths.getStatePaths('init').hasOwnProperty(path);
2457
+ return Object.hasOwn(this.$__.activePaths.getStatePaths('init'), path);
2454
2458
  }
2455
2459
 
2456
2460
  let paths = path;
@@ -2458,7 +2462,7 @@ Document.prototype.isInit = function(path) {
2458
2462
  paths = paths.split(' ');
2459
2463
  }
2460
2464
 
2461
- return paths.some(path => this.$__.activePaths.getStatePaths('init').hasOwnProperty(path));
2465
+ return paths.some(path => Object.hasOwn(this.$__.activePaths.getStatePaths('init'), path));
2462
2466
  };
2463
2467
 
2464
2468
  /**
@@ -2596,7 +2600,7 @@ Document.prototype.isDirectSelected = function isDirectSelected(path) {
2596
2600
  return true;
2597
2601
  }
2598
2602
 
2599
- if (this.$__.selected.hasOwnProperty(path)) {
2603
+ if (Object.hasOwn(this.$__.selected, path)) {
2600
2604
  return inclusive;
2601
2605
  }
2602
2606
 
@@ -2772,7 +2776,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
2772
2776
  if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2773
2777
  // Avoid using isDirectModified() here because that does additional checks on whether the parent path
2774
2778
  // is direct modified, which can cause performance issues re: gh-14897
2775
- !subdocParent.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
2779
+ !Object.hasOwn(subdocParent.$__.activePaths.getStatePaths('modify'), fullPathToSubdoc) &&
2776
2780
  !subdocParent.$isDefault(fullPathToSubdoc)) {
2777
2781
  paths.add(fullPathToSubdoc);
2778
2782
 
@@ -2843,7 +2847,12 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
2843
2847
  // Single nested paths (paths embedded under single nested subdocs) will
2844
2848
  // be validated on their own when we call `validate()` on the subdoc itself.
2845
2849
  // Re: gh-8468
2846
- Object.keys(flat).filter(path => !doc.$__schema.singleNestedPaths.hasOwnProperty(path)).forEach(addToPaths);
2850
+ const singleNestedPaths = doc.$__schema.singleNestedPaths;
2851
+ for (const path of Object.keys(flat)) {
2852
+ if (!Object.hasOwn(singleNestedPaths, path)) {
2853
+ addToPaths(path);
2854
+ }
2855
+ }
2847
2856
  }
2848
2857
  }
2849
2858
 
@@ -4184,7 +4193,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
4184
4193
  }
4185
4194
 
4186
4195
  // Allow skipping aliases with `toObject({ virtuals: true, aliases: false })`
4187
- if (!aliases && schema.aliases.hasOwnProperty(path)) {
4196
+ if (!aliases && Object.hasOwn(schema.aliases, path)) {
4188
4197
  continue;
4189
4198
  }
4190
4199
 
@@ -5097,7 +5106,7 @@ function checkDivergentArray(doc, path, array) {
5097
5106
  // would be similarly destructive as we never received all
5098
5107
  // elements of the array and potentially would overwrite data.
5099
5108
  const check = pop.options.match ||
5100
- pop.options.options && utils.object.hasOwnProperty(pop.options.options, 'limit') || // 0 is not permitted
5109
+ pop.options.options && Object.hasOwn(pop.options.options, 'limit') || // 0 is not permitted
5101
5110
  pop.options.options && pop.options.options.skip || // 0 is permitted
5102
5111
  pop.options.select && // deselected _id?
5103
5112
  (pop.options.select._id === 0 ||
@@ -5422,6 +5431,38 @@ Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValue
5422
5431
  }));
5423
5432
  };
5424
5433
 
5434
+ /*!
5435
+ * Increment this document's version if necessary.
5436
+ */
5437
+
5438
+ Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
5439
+ if (!this.$__.version) return;
5440
+ const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
5441
+
5442
+ this.$__.version = undefined;
5443
+ if (doIncrement) {
5444
+ const key = this.$__schema.options.versionKey;
5445
+ const version = this.$__getValue(key) || 0;
5446
+ this.$__setValue(key, version + 1); // increment version if was successful
5447
+ }
5448
+ };
5449
+
5450
+ /*!
5451
+ * Increment this document's version if necessary.
5452
+ */
5453
+
5454
+ Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
5455
+ if (!this.$__.version) return;
5456
+ const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
5457
+
5458
+ this.$__.version = undefined;
5459
+ if (doIncrement) {
5460
+ const key = this.$__schema.options.versionKey;
5461
+ const version = this.$__getValue(key) || 0;
5462
+ this.$__setValue(key, version + 1); // increment version if was successful
5463
+ }
5464
+ };
5465
+
5425
5466
  /*!
5426
5467
  * Module exports.
5427
5468
  */
@@ -108,7 +108,7 @@ NativeConnection.prototype.useDb = function(name, options) {
108
108
  function wireup() {
109
109
  newConn.client = _this.client;
110
110
  const _opts = {};
111
- if (options.hasOwnProperty('noListener')) {
111
+ if (Object.hasOwn(options, 'noListener')) {
112
112
  _opts.noListener = options.noListener;
113
113
  }
114
114
  newConn.db = _this.client.db(name, _opts);
@@ -515,7 +515,7 @@ function _setClient(conn, client, options, dbName) {
515
515
  conn.onOpen();
516
516
 
517
517
  for (const i in conn.collections) {
518
- if (utils.object.hasOwnProperty(conn.collections, i)) {
518
+ if (Object.hasOwn(conn.collections, i)) {
519
519
  conn.collections[i].onOpen();
520
520
  }
521
521
  }
@@ -20,7 +20,7 @@ class ObjectParameterError extends MongooseError {
20
20
 
21
21
  constructor(value, paramName, fnName) {
22
22
  super('Parameter "' + paramName + '" to ' + fnName +
23
- '() must be an object, got "' + value.toString() + '" (type ' + typeof value + ')');
23
+ '() must be an object, got "' + (value?.toString() ?? (value + '')) + '" (type ' + typeof value + ')');
24
24
  }
25
25
  }
26
26
 
@@ -55,7 +55,7 @@ function flatten(update, path, options, schema) {
55
55
  if (isNested) {
56
56
  const paths = Object.keys(schema.paths);
57
57
  for (const p of paths) {
58
- if (p.startsWith(path + key + '.') && !result.hasOwnProperty(p)) {
58
+ if (p.startsWith(path + key + '.') && !Object.hasOwn(result, p)) {
59
59
  result[p] = void 0;
60
60
  }
61
61
  }
@@ -7,7 +7,7 @@ module.exports = function applySchemaCollation(indexKeys, indexOptions, schemaOp
7
7
  return;
8
8
  }
9
9
 
10
- if (schemaOptions.hasOwnProperty('collation') && !indexOptions.hasOwnProperty('collation')) {
10
+ if (Object.hasOwn(schemaOptions, 'collation') && !Object.hasOwn(indexOptions, 'collation')) {
11
11
  indexOptions.collation = schemaOptions.collation;
12
12
  }
13
13
  };
@@ -14,5 +14,5 @@ module.exports = function isDefaultIdIndex(index) {
14
14
  }
15
15
 
16
16
  const key = get(index, 'key', {});
17
- return Object.keys(key).length === 1 && key.hasOwnProperty('_id');
17
+ return Object.keys(key).length === 1 && Object.hasOwn(key, '_id');
18
18
  };
@@ -28,7 +28,7 @@ module.exports = function applyMethods(model, schema) {
28
28
  }
29
29
  for (const method of Object.keys(schema.methods)) {
30
30
  const fn = schema.methods[method];
31
- if (schema.tree.hasOwnProperty(method)) {
31
+ if (Object.hasOwn(schema.tree, method)) {
32
32
  throw new Error('You have a method and a property in your schema both ' +
33
33
  'named "' + method + '"');
34
34
  }
@@ -118,7 +118,10 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
118
118
  if (model.schema.$timestamps != null && doInitTimestamps) {
119
119
  const createdAt = model.schema.$timestamps.createdAt;
120
120
  const updatedAt = model.schema.$timestamps.updatedAt;
121
- applyTimestampsToUpdate(now, createdAt, updatedAt, update, {});
121
+ applyTimestampsToUpdate(now, createdAt, updatedAt, update, {
122
+ timestamps: updateOne.timestamps,
123
+ overwriteImmutable: updateOne.overwriteImmutable
124
+ });
122
125
  }
123
126
 
124
127
  if (doInitTimestamps) {
@@ -150,7 +153,8 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
150
153
  strict: strict,
151
154
  upsert: updateOne.upsert,
152
155
  arrayFilters: updateOne.arrayFilters,
153
- overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey
156
+ overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey,
157
+ overwriteImmutable: updateOne.overwriteImmutable
154
158
  }, model, updateOne['filter']);
155
159
 
156
160
  return updateOne;
@@ -185,7 +189,10 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
185
189
  if (model.schema.$timestamps != null && doInitTimestamps) {
186
190
  const createdAt = model.schema.$timestamps.createdAt;
187
191
  const updatedAt = model.schema.$timestamps.updatedAt;
188
- applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {});
192
+ applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {
193
+ timestamps: updateMany.timestamps,
194
+ overwriteImmutable: updateMany.overwriteImmutable
195
+ });
189
196
  }
190
197
  if (doInitTimestamps) {
191
198
  applyTimestampsToChildren(now, updateMany['update'], model.schema);
@@ -208,7 +215,8 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
208
215
  strict: strict,
209
216
  upsert: updateMany.upsert,
210
217
  arrayFilters: updateMany.arrayFilters,
211
- overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey
218
+ overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey,
219
+ overwriteImmutable: updateMany.overwriteImmutable
212
220
  }, model, updateMany['filter']);
213
221
  };
214
222
 
@@ -289,13 +297,12 @@ function _addDiscriminatorToObject(schema, obj) {
289
297
 
290
298
  function decideModelByObject(model, object) {
291
299
  const discriminatorKey = model.schema.options.discriminatorKey;
292
- if (object != null && object.hasOwnProperty(discriminatorKey)) {
300
+ if (object != null && Object.hasOwn(object, discriminatorKey)) {
293
301
  model = getDiscriminatorByValue(model.discriminators, object[discriminatorKey]) || model;
294
302
  }
295
303
  return model;
296
304
  }
297
305
 
298
-
299
306
  /**
300
307
  * gets timestamps option for a given operation. If the option is set within an individual operation, use it. Otherwise, use the global timestamps option configured in the `bulkWrite` options. Overall default is `true`.
301
308
  * @api private
@@ -386,13 +386,13 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
386
386
  }
387
387
  data.count = virtual.options.count;
388
388
 
389
- if (virtual.options.skip != null && !options.hasOwnProperty('skip')) {
389
+ if (virtual.options.skip != null && !Object.hasOwn(options, 'skip')) {
390
390
  options.skip = virtual.options.skip;
391
391
  }
392
- if (virtual.options.limit != null && !options.hasOwnProperty('limit')) {
392
+ if (virtual.options.limit != null && !Object.hasOwn(options, 'limit')) {
393
393
  options.limit = virtual.options.limit;
394
394
  }
395
- if (virtual.options.perDocumentLimit != null && !options.hasOwnProperty('perDocumentLimit')) {
395
+ if (virtual.options.perDocumentLimit != null && !Object.hasOwn(options, 'perDocumentLimit')) {
396
396
  options.perDocumentLimit = virtual.options.perDocumentLimit;
397
397
  }
398
398
  let foreignField = virtual.options.foreignField;
@@ -56,7 +56,7 @@ module.exports = function modelNamesFromRefPath(refPath, doc, populatedPath, mod
56
56
  const refValue = mpath.get(refPath, doc, lookupLocalFields);
57
57
 
58
58
  let modelNames;
59
- if (modelSchema != null && modelSchema.virtuals.hasOwnProperty(refPath)) {
59
+ if (modelSchema != null && Object.hasOwn(modelSchema.virtuals, refPath)) {
60
60
  modelNames = [modelSchema.virtuals[refPath].applyGetters(void 0, doc)];
61
61
  } else {
62
62
  modelNames = Array.isArray(refValue) ? refValue : [refValue];
@@ -16,7 +16,7 @@ module.exports = function removeDeselectedForeignField(foreignFields, options, d
16
16
  return;
17
17
  }
18
18
  for (const foreignField of foreignFields) {
19
- if (!projection.hasOwnProperty('-' + foreignField)) {
19
+ if (!Object.hasOwn(projection, '-' + foreignField)) {
20
20
  continue;
21
21
  }
22
22
 
@@ -43,7 +43,7 @@ function applyExclusiveProjection(doc, projection, hasIncludedChildren, projecti
43
43
 
44
44
  for (const key of Object.keys(ret)) {
45
45
  const fullPath = prefix ? prefix + '.' + key : key;
46
- if (projection.hasOwnProperty(fullPath) || projectionLimb.hasOwnProperty(key)) {
46
+ if (Object.hasOwn(projection, fullPath) || Object.hasOwn(projectionLimb, key)) {
47
47
  if (isPOJO(projection[fullPath]) || isPOJO(projectionLimb[key])) {
48
48
  ret[key] = applyExclusiveProjection(ret[key], projection, hasIncludedChildren, projectionLimb[key], fullPath);
49
49
  } else {
@@ -68,7 +68,7 @@ function applyInclusiveProjection(doc, projection, hasIncludedChildren, projecti
68
68
 
69
69
  for (const key of Object.keys(ret)) {
70
70
  const fullPath = prefix ? prefix + '.' + key : key;
71
- if (projection.hasOwnProperty(fullPath) || projectionLimb.hasOwnProperty(key)) {
71
+ if (Object.hasOwn(projection, fullPath) || Object.hasOwn(projectionLimb, key)) {
72
72
  if (isPOJO(projection[fullPath]) || isPOJO(projectionLimb[key])) {
73
73
  ret[key] = applyInclusiveProjection(ret[key], projection, hasIncludedChildren, projectionLimb[key], fullPath);
74
74
  }
@@ -71,7 +71,7 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
71
71
  const schemaKey = updatedPathsByFilter[filterKey] + '.' + key;
72
72
  const arrayFilterKey = filterKey + '.' + key;
73
73
  if (schemaKey === discriminatorFilterPath) {
74
- const filter = arrayFilters.find(filter => filter.hasOwnProperty(arrayFilterKey));
74
+ const filter = arrayFilters.find(filter => Object.hasOwn(filter, arrayFilterKey));
75
75
  if (filter != null) {
76
76
  discriminatorKey = filter[arrayFilterKey];
77
77
  }
@@ -136,14 +136,14 @@ function pathExistsInUpdate(update, targetPath, pathPieces) {
136
136
  }
137
137
 
138
138
  // Check exact match
139
- if (update.hasOwnProperty(targetPath)) {
139
+ if (Object.hasOwn(update, targetPath)) {
140
140
  return true;
141
141
  }
142
142
 
143
143
  // Check if any parent path exists
144
144
  let cur = pathPieces[0];
145
145
  for (let i = 1; i < pathPieces.length; ++i) {
146
- if (update.hasOwnProperty(cur)) {
146
+ if (Object.hasOwn(update, cur)) {
147
147
  return true;
148
148
  }
149
149
  cur += '.' + pathPieces[i];
@@ -23,7 +23,7 @@ module.exports = function setupTimestamps(schema, timestamps) {
23
23
  }
24
24
  const createdAt = handleTimestampOption(timestamps, 'createdAt');
25
25
  const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
26
- const currentTime = timestamps != null && timestamps.hasOwnProperty('currentTime') ?
26
+ const currentTime = timestamps != null && Object.hasOwn(timestamps, 'currentTime') ?
27
27
  timestamps.currentTime :
28
28
  null;
29
29
  const schemaAdditions = {};
@@ -74,39 +74,52 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
74
74
  updates.$set[updatedAt] = now;
75
75
  }
76
76
 
77
- if (updates.hasOwnProperty(updatedAt)) {
77
+ if (Object.hasOwn(updates, updatedAt)) {
78
78
  delete updates[updatedAt];
79
79
  }
80
80
  }
81
81
 
82
82
  if (!skipCreatedAt && createdAt) {
83
- if (currentUpdate[createdAt]) {
84
- delete currentUpdate[createdAt];
85
- }
86
- if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
87
- delete currentUpdate.$set[createdAt];
88
- }
89
- let timestampSet = false;
90
- if (createdAt.indexOf('.') !== -1) {
91
- const pieces = createdAt.split('.');
92
- for (let i = 1; i < pieces.length; ++i) {
93
- const remnant = pieces.slice(-i).join('.');
94
- const start = pieces.slice(0, -i).join('.');
95
- if (currentUpdate[start] != null) {
96
- currentUpdate[start][remnant] = now;
97
- timestampSet = true;
98
- break;
99
- } else if (currentUpdate.$set && currentUpdate.$set[start]) {
100
- currentUpdate.$set[start][remnant] = now;
101
- timestampSet = true;
102
- break;
83
+ const overwriteImmutable = get(options, 'overwriteImmutable', false);
84
+ const hasUserCreatedAt = currentUpdate[createdAt] != null || currentUpdate?.$set[createdAt] != null;
85
+
86
+ // If overwriteImmutable is true and user provided createdAt, keep their value
87
+ if (overwriteImmutable && hasUserCreatedAt) {
88
+ // Move createdAt from top-level to $set if needed
89
+ if (currentUpdate[createdAt] != null) {
90
+ updates.$set[createdAt] = currentUpdate[createdAt];
91
+ delete currentUpdate[createdAt];
92
+ }
93
+ // User's value is already in $set, nothing more to do
94
+ } else {
95
+ if (currentUpdate[createdAt]) {
96
+ delete currentUpdate[createdAt];
97
+ }
98
+ if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
99
+ delete currentUpdate.$set[createdAt];
100
+ }
101
+ let timestampSet = false;
102
+ if (createdAt.indexOf('.') !== -1) {
103
+ const pieces = createdAt.split('.');
104
+ for (let i = 1; i < pieces.length; ++i) {
105
+ const remnant = pieces.slice(-i).join('.');
106
+ const start = pieces.slice(0, -i).join('.');
107
+ if (currentUpdate[start] != null) {
108
+ currentUpdate[start][remnant] = now;
109
+ timestampSet = true;
110
+ break;
111
+ } else if (currentUpdate.$set && currentUpdate.$set[start]) {
112
+ currentUpdate.$set[start][remnant] = now;
113
+ timestampSet = true;
114
+ break;
115
+ }
103
116
  }
104
117
  }
105
- }
106
118
 
107
- if (!timestampSet) {
108
- updates.$setOnInsert = updates.$setOnInsert || {};
109
- updates.$setOnInsert[createdAt] = now;
119
+ if (!timestampSet) {
120
+ updates.$setOnInsert = updates.$setOnInsert || {};
121
+ updates.$setOnInsert[createdAt] = now;
122
+ }
110
123
  }
111
124
  }
112
125
 
@@ -31,5 +31,5 @@ function hasKey(obj, key) {
31
31
  if (obj == null || typeof obj !== 'object') {
32
32
  return false;
33
33
  }
34
- return Object.prototype.hasOwnProperty.call(obj, key);
34
+ return Object.hasOwn(obj, key);
35
35
  }