mongoose 9.0.0 → 9.0.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.
Files changed (38) hide show
  1. package/lib/aggregate.js +1 -1
  2. package/lib/cast/double.js +1 -1
  3. package/lib/cast.js +1 -1
  4. package/lib/connection.js +10 -10
  5. package/lib/document.js +54 -17
  6. package/lib/drivers/node-mongodb-native/collection.js +16 -1
  7. package/lib/drivers/node-mongodb-native/connection.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 +8 -7
  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/number.js +14 -2
  27. package/lib/schema/operators/text.js +1 -1
  28. package/lib/schema.js +21 -21
  29. package/lib/schemaType.js +8 -8
  30. package/lib/types/array/index.js +5 -5
  31. package/lib/types/documentArray/index.js +6 -6
  32. package/lib/types/objectid.js +1 -1
  33. package/lib/utils.js +12 -24
  34. package/lib/virtualType.js +1 -1
  35. package/package.json +7 -7
  36. package/types/index.d.ts +1 -0
  37. package/types/models.d.ts +313 -85
  38. package/types/query.d.ts +91 -1
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
 
@@ -34,7 +34,7 @@ module.exports = function castDouble(val) {
34
34
  // ex: { a: 'im an object, valueOf: () => 'helloworld' } // throw an error
35
35
  if (typeof tempVal === 'string') {
36
36
  try {
37
- coercedVal = BSON.Double.fromString(val);
37
+ coercedVal = BSON.Double.fromString(tempVal);
38
38
  return coercedVal;
39
39
  } catch {
40
40
  assert.ok(false);
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
  }
@@ -1782,7 +1782,7 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) {
1782
1782
  };
1783
1783
 
1784
1784
  /**
1785
- * Switches to a different database using the same [connection pool](https://mongoosejs.com/docs/api/connectionshtml#connection_pools).
1785
+ * Switches to a different database using the same [connection pool](https://mongoosejs.com/docs/connections.html#connection_pools).
1786
1786
  *
1787
1787
  * Returns a new connection object, with the new db.
1788
1788
  *
package/lib/document.js CHANGED
@@ -784,7 +784,7 @@ function init(self, obj, doc, opts, prefix) {
784
784
  }
785
785
  } else {
786
786
  // Retain order when overwriting defaults
787
- if (doc.hasOwnProperty(i) && value !== void 0 && !opts.hydratedPopulatedDocs) {
787
+ if (Object.hasOwn(doc, i) && value !== void 0 && !opts.hydratedPopulatedDocs) {
788
788
  delete doc[i];
789
789
  }
790
790
  if (value === null) {
@@ -1167,7 +1167,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1167
1167
  const orderedKeys = Object.keys(this.$__schema.tree);
1168
1168
  for (let i = 0, len = orderedKeys.length; i < len; ++i) {
1169
1169
  (key = orderedKeys[i]) &&
1170
- (this._doc.hasOwnProperty(key)) &&
1170
+ (Object.hasOwn(this._doc, key)) &&
1171
1171
  (orderedDoc[key] = undefined);
1172
1172
  }
1173
1173
  this._doc = Object.assign(orderedDoc, this._doc);
@@ -1217,8 +1217,8 @@ Document.prototype.$set = function $set(path, val, type, options) {
1217
1217
  return this;
1218
1218
  }
1219
1219
  const wasModified = this.$isModified(path);
1220
- const hasInitialVal = this.$__.savedState != null && this.$__.savedState.hasOwnProperty(path);
1221
- if (this.$__.savedState != null && !this.$isNew && !this.$__.savedState.hasOwnProperty(path)) {
1220
+ const hasInitialVal = this.$__.savedState != null && Object.hasOwn(this.$__.savedState, path);
1221
+ if (this.$__.savedState != null && !this.$isNew && !Object.hasOwn(this.$__.savedState, path)) {
1222
1222
  const initialVal = this.$__getValue(path);
1223
1223
  this.$__.savedState[path] = initialVal;
1224
1224
 
@@ -1523,7 +1523,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1523
1523
  this.$__.session[sessionNewDocuments].get(this).modifiedPaths &&
1524
1524
  !this.$__.session[sessionNewDocuments].get(this).modifiedPaths.has(savedStatePath);
1525
1525
  if (savedState != null &&
1526
- savedState.hasOwnProperty(savedStatePath) &&
1526
+ Object.hasOwn(savedState, savedStatePath) &&
1527
1527
  (!isInTransaction || isModifiedWithinTransaction) &&
1528
1528
  utils.deepEqual(val, savedState[savedStatePath])) {
1529
1529
  this.unmarkModified(path);
@@ -2005,7 +2005,7 @@ Document.prototype.$get = Document.prototype.get;
2005
2005
 
2006
2006
  Document.prototype.$__path = function(path) {
2007
2007
  const adhocs = this.$__.adhocPaths;
2008
- const adhocType = adhocs && adhocs.hasOwnProperty(path) ? adhocs[path] : null;
2008
+ const adhocType = adhocs && Object.hasOwn(adhocs, path) ? adhocs[path] : null;
2009
2009
 
2010
2010
  if (adhocType) {
2011
2011
  return adhocType;
@@ -2049,7 +2049,7 @@ Document.prototype.$__saveInitialState = function $__saveInitialState(path) {
2049
2049
  if (savedState != null) {
2050
2050
  const firstDot = savedStatePath.indexOf('.');
2051
2051
  const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
2052
- if (!savedState.hasOwnProperty(topLevelPath)) {
2052
+ if (!Object.hasOwn(savedState, topLevelPath)) {
2053
2053
  savedState[topLevelPath] = clone(this.$__getValue(topLevelPath));
2054
2054
  }
2055
2055
  }
@@ -2360,7 +2360,7 @@ Document.prototype.$isDefault = function(path) {
2360
2360
  }
2361
2361
 
2362
2362
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2363
- return this.$__.activePaths.getStatePaths('default').hasOwnProperty(path);
2363
+ return Object.hasOwn(this.$__.activePaths.getStatePaths('default'), path);
2364
2364
  }
2365
2365
 
2366
2366
  let paths = path;
@@ -2368,7 +2368,7 @@ Document.prototype.$isDefault = function(path) {
2368
2368
  paths = paths.split(' ');
2369
2369
  }
2370
2370
 
2371
- return paths.some(path => this.$__.activePaths.getStatePaths('default').hasOwnProperty(path));
2371
+ return paths.some(path => Object.hasOwn(this.$__.activePaths.getStatePaths('default'), path));
2372
2372
  };
2373
2373
 
2374
2374
  /**
@@ -2422,7 +2422,7 @@ Document.prototype.isDirectModified = function(path) {
2422
2422
  }
2423
2423
 
2424
2424
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2425
- const res = this.$__.activePaths.getStatePaths('modify').hasOwnProperty(path);
2425
+ const res = Object.hasOwn(this.$__.activePaths.getStatePaths('modify'), path);
2426
2426
  if (res || path.indexOf('.') === -1) {
2427
2427
  return res;
2428
2428
  }
@@ -2461,7 +2461,7 @@ Document.prototype.isInit = function(path) {
2461
2461
  }
2462
2462
 
2463
2463
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2464
- return this.$__.activePaths.getStatePaths('init').hasOwnProperty(path);
2464
+ return Object.hasOwn(this.$__.activePaths.getStatePaths('init'), path);
2465
2465
  }
2466
2466
 
2467
2467
  let paths = path;
@@ -2469,7 +2469,7 @@ Document.prototype.isInit = function(path) {
2469
2469
  paths = paths.split(' ');
2470
2470
  }
2471
2471
 
2472
- return paths.some(path => this.$__.activePaths.getStatePaths('init').hasOwnProperty(path));
2472
+ return paths.some(path => Object.hasOwn(this.$__.activePaths.getStatePaths('init'), path));
2473
2473
  };
2474
2474
 
2475
2475
  /**
@@ -2607,7 +2607,7 @@ Document.prototype.isDirectSelected = function isDirectSelected(path) {
2607
2607
  return true;
2608
2608
  }
2609
2609
 
2610
- if (this.$__.selected.hasOwnProperty(path)) {
2610
+ if (Object.hasOwn(this.$__.selected, path)) {
2611
2611
  return inclusive;
2612
2612
  }
2613
2613
 
@@ -2779,7 +2779,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
2779
2779
  if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2780
2780
  // Avoid using isDirectModified() here because that does additional checks on whether the parent path
2781
2781
  // is direct modified, which can cause performance issues re: gh-14897
2782
- !subdocParent.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
2782
+ !Object.hasOwn(subdocParent.$__.activePaths.getStatePaths('modify'), fullPathToSubdoc) &&
2783
2783
  !subdocParent.$isDefault(fullPathToSubdoc)) {
2784
2784
  paths.add(fullPathToSubdoc);
2785
2785
 
@@ -2850,7 +2850,12 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
2850
2850
  // Single nested paths (paths embedded under single nested subdocs) will
2851
2851
  // be validated on their own when we call `validate()` on the subdoc itself.
2852
2852
  // Re: gh-8468
2853
- Object.keys(flat).filter(path => !doc.$__schema.singleNestedPaths.hasOwnProperty(path)).forEach(addToPaths);
2853
+ const singleNestedPaths = doc.$__schema.singleNestedPaths;
2854
+ for (const path of Object.keys(flat)) {
2855
+ if (!Object.hasOwn(singleNestedPaths, path)) {
2856
+ addToPaths(path);
2857
+ }
2858
+ }
2854
2859
  }
2855
2860
  }
2856
2861
 
@@ -4188,7 +4193,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
4188
4193
  }
4189
4194
 
4190
4195
  // Allow skipping aliases with `toObject({ virtuals: true, aliases: false })`
4191
- if (!aliases && schema.aliases.hasOwnProperty(path)) {
4196
+ if (!aliases && Object.hasOwn(schema.aliases, path)) {
4192
4197
  continue;
4193
4198
  }
4194
4199
 
@@ -5101,7 +5106,7 @@ function checkDivergentArray(doc, path, array) {
5101
5106
  // would be similarly destructive as we never received all
5102
5107
  // elements of the array and potentially would overwrite data.
5103
5108
  const check = pop.options.match ||
5104
- 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
5105
5110
  pop.options.options && pop.options.options.skip || // 0 is permitted
5106
5111
  pop.options.select && // deselected _id?
5107
5112
  (pop.options.select._id === 0 ||
@@ -5426,6 +5431,38 @@ Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValue
5426
5431
  }));
5427
5432
  };
5428
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
+
5429
5466
  /*!
5430
5467
  * Module exports.
5431
5468
  */
@@ -124,6 +124,7 @@ function iter(i) {
124
124
 
125
125
  let _args = args;
126
126
  let callback = null;
127
+ let timeout = null;
127
128
  if (this._shouldBufferCommands() && this.buffer) {
128
129
  this.conn.emit('buffer', {
129
130
  _id: opId,
@@ -136,7 +137,6 @@ function iter(i) {
136
137
  let callback;
137
138
  let _args = args;
138
139
  let promise = null;
139
- let timeout = null;
140
140
  if (syncCollectionMethods[i] && typeof lastArg === 'function') {
141
141
  this.addQueue(i, _args);
142
142
  callback = lastArg;
@@ -239,6 +239,9 @@ function iter(i) {
239
239
 
240
240
  if (syncCollectionMethods[i] && typeof lastArg === 'function') {
241
241
  const result = collection[i].apply(collection, _args.slice(0, _args.length - 1));
242
+ if (timeout != null) {
243
+ clearTimeout(timeout);
244
+ }
242
245
  this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result });
243
246
  return lastArg.call(this, null, result);
244
247
  }
@@ -247,6 +250,9 @@ function iter(i) {
247
250
  if (ret != null && typeof ret.then === 'function') {
248
251
  return ret.then(
249
252
  result => {
253
+ if (timeout != null) {
254
+ clearTimeout(timeout);
255
+ }
250
256
  if (typeof lastArg === 'function') {
251
257
  lastArg(null, result);
252
258
  } else {
@@ -255,6 +261,9 @@ function iter(i) {
255
261
  return result;
256
262
  },
257
263
  error => {
264
+ if (timeout != null) {
265
+ clearTimeout(timeout);
266
+ }
258
267
  if (typeof lastArg === 'function') {
259
268
  lastArg(error);
260
269
  return;
@@ -265,10 +274,16 @@ function iter(i) {
265
274
  }
266
275
  );
267
276
  }
277
+ if (timeout != null) {
278
+ clearTimeout(timeout);
279
+ }
268
280
  return ret;
269
281
  } catch (error) {
270
282
  // Collection operation may throw because of max bson size, catch it here
271
283
  // See gh-3906
284
+ if (timeout != null) {
285
+ clearTimeout(timeout);
286
+ }
272
287
  if (typeof lastArg === 'function') {
273
288
  return lastArg(error);
274
289
  } else {
@@ -508,7 +508,7 @@ function _setClient(conn, client, options, dbName) {
508
508
  conn.onOpen();
509
509
 
510
510
  for (const i in conn.collections) {
511
- if (utils.object.hasOwnProperty(conn.collections, i)) {
511
+ if (Object.hasOwn(conn.collections, i)) {
512
512
  conn.collections[i].onOpen();
513
513
  }
514
514
  }
@@ -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
  }