From d14e94d6c834ce7d6c519c89fb9ef889a4fcac2f Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 17 Oct 2023 12:22:51 -0400 Subject: [PATCH 1/9] BREAKING CHANGE: remove support for overwrite option setting findOneAndUpdate to findOneAndReplace Re: #13578 --- lib/query.js | 19 ------------------- test/query.test.js | 10 ---------- types/inferschematype.d.ts | 10 +++++----- 3 files changed, 5 insertions(+), 34 deletions(-) diff --git a/lib/query.js b/lib/query.js index 6b410d61c77..f048b3c5660 100644 --- a/lib/query.js +++ b/lib/query.js @@ -1670,15 +1670,6 @@ Query.prototype.setOptions = function(options, overwrite) { return this; }; -/*! - * ignore - */ - -const printOverwriteDeprecationWarning = util.deprecate( - function printOverwriteDeprecationWarning() {}, - 'The `overwrite` option for `findOneAndUpdate()` is deprecated. use `findOneAndReplace()` instead.' -); - /** * Sets the [`explain` option](https://www.mongodb.com/docs/manual/reference/method/cursor.explain/), * which makes this query return detailed execution stats instead of the actual @@ -3259,16 +3250,6 @@ Query.prototype.findOneAndUpdate = function(filter, doc, options) { */ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() { - // For backwards compability with Mongoose 6 re: #13550 - - if (this._mongooseOptions.overwrite != null) { - printOverwriteDeprecationWarning(); - } - if (this._mongooseOptions.overwrite) { - this.op = 'findOneAndReplace'; - return this._findOneAndReplace(); - } - this._castConditions(); _castArrayFilters(this); diff --git a/test/query.test.js b/test/query.test.js index 2c357b82fa1..1c4c86440b2 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -4156,16 +4156,6 @@ describe('Query', function() { /Query must have `op` before executing/ ); }); - it('converts findOneAndUpdate to findOneAndReplace if overwrite set (gh-13550)', async function() { - const testSchema = new Schema({ - name: { type: String } - }); - - const Test = db.model('Test', testSchema); - const q = Test.findOneAndUpdate({}, { name: 'bar' }, { overwrite: true }); - await q.exec(); - assert.equal(q.op, 'findOneAndReplace'); - }); it('allows deselecting discriminator key (gh-13760) (gh-13679)', async function() { const testSchema = new Schema({ name: String, age: Number }); diff --git a/types/inferschematype.d.ts b/types/inferschematype.d.ts index 98e5fd2ff7a..e4ea5ebe327 100644 --- a/types/inferschematype.d.ts +++ b/types/inferschematype.d.ts @@ -32,14 +32,14 @@ declare module 'mongoose' { EnforcedDocType : { [ - K in keyof (RequiredPaths & - OptionalPaths) + K in keyof (RequiredPaths & + OptionalPaths) ]: IsPathRequired extends true ? ObtainDocumentPathType : ObtainDocumentPathType | null; - }; + }; - /** + /** * @summary Obtains document schema type from Schema instance. * @param {Schema} TSchema `typeof` a schema instance. * @example @@ -48,7 +48,7 @@ declare module 'mongoose' { * // result * type UserType = {userName?: string} */ - export type InferSchemaType = IfAny>; + export type InferSchemaType = IfAny>; /** * @summary Obtains schema Generic type by using generic alias. From f50d88dbc257730bc7546176eb084ddb9b8e36cd Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 17 Oct 2023 12:38:43 -0400 Subject: [PATCH 2/9] refactor: avoid relying on overwrite option for timestamps and casting re: #13578 --- lib/helpers/timestamps/setupTimestamps.js | 2 +- lib/helpers/update/applyTimestampsToUpdate.js | 5 ++--- lib/query.js | 10 +--------- test/query.test.js | 11 ----------- 4 files changed, 4 insertions(+), 24 deletions(-) diff --git a/lib/helpers/timestamps/setupTimestamps.js b/lib/helpers/timestamps/setupTimestamps.js index 78293deb904..f6ba12b98b6 100644 --- a/lib/helpers/timestamps/setupTimestamps.js +++ b/lib/helpers/timestamps/setupTimestamps.js @@ -102,7 +102,7 @@ module.exports = function setupTimestamps(schema, timestamps) { updatedAt, this.getUpdate(), this._mongooseOptions, - this.schema + replaceOps.has(this.op) ); applyTimestampsToChildren(now, this.getUpdate(), this.model.schema); next(); diff --git a/lib/helpers/update/applyTimestampsToUpdate.js b/lib/helpers/update/applyTimestampsToUpdate.js index b48febafb69..e8d3217fbb9 100644 --- a/lib/helpers/update/applyTimestampsToUpdate.js +++ b/lib/helpers/update/applyTimestampsToUpdate.js @@ -12,10 +12,9 @@ module.exports = applyTimestampsToUpdate; * ignore */ -function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, options) { +function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, options, isReplace) { const updates = currentUpdate; let _updates = updates; - const overwrite = get(options, 'overwrite', false); const timestamps = get(options, 'timestamps', true); // Support skipping timestamps at the query level, see gh-6980 @@ -26,7 +25,7 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio const skipCreatedAt = timestamps != null && timestamps.createdAt === false; const skipUpdatedAt = timestamps != null && timestamps.updatedAt === false; - if (overwrite) { + if (isReplace) { if (currentUpdate && currentUpdate.$set) { currentUpdate = currentUpdate.$set; updates.$set = {}; diff --git a/lib/query.js b/lib/query.js index f048b3c5660..ef945402c33 100644 --- a/lib/query.js +++ b/lib/query.js @@ -21,7 +21,6 @@ const castUpdate = require('./helpers/query/castUpdate'); const clone = require('./helpers/clone'); const completeMany = require('./helpers/query/completeMany'); const getDiscriminatorByValue = require('./helpers/discriminator/getDiscriminatorByValue'); -const hasDollarKeys = require('./helpers/query/hasDollarKeys'); const helpers = require('./queryHelpers'); const immediate = require('./helpers/immediate'); const internalToObjectOptions = require('./options').internalToObjectOptions; @@ -3501,7 +3500,6 @@ Query.prototype.findOneAndReplace = function(filter, replacement, options) { options.returnOriginal = returnOriginal; } this.setOptions(options); - this.setOptions({ overwrite: true }); return this; }; @@ -3736,13 +3734,8 @@ async function _updateThunk(op) { this._applyTranslateAliases(options); this._update = clone(this._update, options); - const isOverwriting = this._mongooseOptions.overwrite && !hasDollarKeys(this._update); + const isOverwriting = op === 'replaceOne'; if (isOverwriting) { - if (op === 'updateOne' || op === 'updateMany') { - throw new MongooseError('The MongoDB server disallows ' + - 'overwriting documents using `' + op + '`. See: ' + - 'https://mongoosejs.com/docs/deprecations.html#update'); - } this._update = new this.model(this._update, null, true); } else { this._update = this._castUpdate(this._update, this._mongooseOptions.overwrite); @@ -4046,7 +4039,6 @@ Query.prototype.replaceOne = function(conditions, doc, options, callback) { callback = undefined; } - this.setOptions({ overwrite: true }); return _update(this, 'replaceOne', conditions, doc, options, callback); }; diff --git a/test/query.test.js b/test/query.test.js index 1c4c86440b2..5cba1f62c1e 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -2962,17 +2962,6 @@ describe('Query', function() { delete db.base.options.maxTimeMS; }); - it('throws error with updateOne() and overwrite (gh-7475)', function() { - const Model = db.model('Test', Schema({ name: String })); - - return Model.updateOne({}, { name: 'bar' }, { overwrite: true }).then( - () => { throw new Error('Should have failed'); }, - err => { - assert.ok(err.message.indexOf('updateOne') !== -1); - } - ); - }); - describe('merge()', function() { it('copies populate() (gh-1790)', async function() { const Car = db.model('Car', { From 7722af49accefd8de2cbe9d29b972c18babfdcbf Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 17 Oct 2023 13:10:31 -0400 Subject: [PATCH 3/9] refactor: remove `overwrite` from castUpdate --- lib/helpers/query/castUpdate.js | 11 +++-------- lib/query.js | 3 +-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/helpers/query/castUpdate.js b/lib/helpers/query/castUpdate.js index 78422033079..f9b90beb946 100644 --- a/lib/helpers/query/castUpdate.js +++ b/lib/helpers/query/castUpdate.js @@ -38,7 +38,6 @@ const mongodbUpdateOperators = new Set([ * @param {Schema} schema * @param {Object} obj * @param {Object} [options] - * @param {Boolean} [options.overwrite] defaults to false * @param {Boolean|String} [options.strict] defaults to true * @param {Query} context passed to setters * @return {Boolean} true iff the update is non-empty @@ -61,7 +60,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) { return obj; } - if (options.upsert && !options.overwrite) { + if (options.upsert) { moveImmutableProperties(schema, obj, context); } @@ -70,13 +69,11 @@ module.exports = function castUpdate(schema, obj, options, context, filter) { const ret = {}; let val; let hasDollarKey = false; - const overwrite = options.overwrite; filter = filter || {}; while (i--) { const op = ops[i]; - // if overwrite is set, don't do any of the special $set stuff - if (!mongodbUpdateOperators.has(op) && !overwrite) { + if (!mongodbUpdateOperators.has(op)) { // fix up $set sugar if (!ret.$set) { if (obj.$set) { @@ -106,10 +103,8 @@ module.exports = function castUpdate(schema, obj, options, context, filter) { if (val && typeof val === 'object' && !Buffer.isBuffer(val) && - (!overwrite || mongodbUpdateOperators.has(op))) { + mongodbUpdateOperators.has(op)) { walkUpdatePath(schema, val, op, options, context, filter); - } else if (overwrite && ret && typeof ret === 'object') { - walkUpdatePath(schema, ret, '$set', options, context, filter); } else { const msg = 'Invalid atomic update value for ' + op + '. ' + 'Expected an object, received ' + typeof val; diff --git a/lib/query.js b/lib/query.js index ef945402c33..036f0d5f98c 100644 --- a/lib/query.js +++ b/lib/query.js @@ -4544,7 +4544,7 @@ Query.prototype.post = function(fn) { * @api private */ -Query.prototype._castUpdate = function _castUpdate(obj, overwrite) { +Query.prototype._castUpdate = function _castUpdate(obj) { let schema = this.schema; const discriminatorKey = schema.options.discriminatorKey; @@ -4578,7 +4578,6 @@ Query.prototype._castUpdate = function _castUpdate(obj, overwrite) { } return castUpdate(schema, obj, { - overwrite: overwrite, strict: this._mongooseOptions.strict, upsert: upsert, arrayFilters: this.options.arrayFilters, From f6ed0eb2e86b1b03ce1c413a957745d0e7ffb1a2 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 17 Oct 2023 13:30:05 -0400 Subject: [PATCH 4/9] refactor: remove remaining usage of `overwrite` option Re: #13578 --- lib/helpers/model/castBulkWrite.js | 2 - lib/helpers/query/castUpdate.js | 2 - lib/model.js | 15 ++----- lib/query.js | 14 +----- test/model.updateOne.test.js | 68 ------------------------------ 5 files changed, 5 insertions(+), 96 deletions(-) diff --git a/lib/helpers/model/castBulkWrite.js b/lib/helpers/model/castBulkWrite.js index fb3dab06161..5a4f6f7b316 100644 --- a/lib/helpers/model/castBulkWrite.js +++ b/lib/helpers/model/castBulkWrite.js @@ -88,7 +88,6 @@ module.exports = function castBulkWrite(originalModel, op, options) { op['updateOne']['update'] = castUpdate(model.schema, op['updateOne']['update'], { strict: strict, - overwrite: false, upsert: op['updateOne'].upsert }, model, op['updateOne']['filter']); } catch (error) { @@ -140,7 +139,6 @@ module.exports = function castBulkWrite(originalModel, op, options) { op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], { strict: strict, - overwrite: false, upsert: op['updateMany'].upsert }, model, op['updateMany']['filter']); } catch (error) { diff --git a/lib/helpers/query/castUpdate.js b/lib/helpers/query/castUpdate.js index f9b90beb946..a300190f194 100644 --- a/lib/helpers/query/castUpdate.js +++ b/lib/helpers/query/castUpdate.js @@ -233,7 +233,6 @@ function walkUpdatePath(schema, obj, op, options, context, filter, pref) { } if (op !== '$setOnInsert' && - !options.overwrite && handleImmutable(schematype, strict, obj, key, prefix + key, context)) { continue; } @@ -328,7 +327,6 @@ function walkUpdatePath(schema, obj, op, options, context, filter, pref) { // You can use `$setOnInsert` with immutable keys if (op !== '$setOnInsert' && - !options.overwrite && handleImmutable(schematype, strict, obj, key, prefix + key, context)) { continue; } diff --git a/lib/model.js b/lib/model.js index 1d01a20b807..c5db2420647 100644 --- a/lib/model.js +++ b/lib/model.js @@ -2394,7 +2394,6 @@ Model.$where = function $where() { * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html). * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set. - * @param {Boolean} [options.overwrite=false] If set to `true`, Mongoose will convert this `findOneAndUpdate()` to a `findOneAndReplace()`. This option is deprecated and only supported for backwards compatiblity. * @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document * @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select()) * @param {Boolean} [options.new=false] if true, return the modified document rather than the original @@ -2453,14 +2452,10 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) { const updatedPaths = modifiedPaths(update); if (!updatedPaths[versionKey]) { - if (options.overwrite) { - update[versionKey] = 0; - } else { - if (!update.$setOnInsert) { - update.$setOnInsert = {}; - } - update.$setOnInsert[versionKey] = 0; + if (!update.$setOnInsert) { + update.$setOnInsert = {}; } + update.$setOnInsert[versionKey] = 0; } } @@ -2492,9 +2487,6 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) { * // is sent as * Model.findByIdAndUpdate(id, { $set: { name: 'jason bourne' }}, options) * - * This helps prevent accidentally overwriting your document with `{ name: 'jason bourne' }`. - * To prevent this behaviour, see the `overwrite` option - * * #### Note: * * `findOneAndX` and `findByIdAndX` functions support limited validation. You can @@ -2515,7 +2507,6 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) { * @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html). * @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict) * @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set. - * @param {Boolean} [options.overwrite=false] If set to `true`, Mongoose will convert this `findByIdAndUpdate()` to a `findByIdAndReplace()`. This option is deprecated and only supported for backwards compatiblity. * @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update. * @param {Boolean} [options.runValidators] if true, runs [update validators](https://mongoosejs.com/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema * @param {Boolean} [options.setDefaultsOnInsert=true] If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created diff --git a/lib/query.js b/lib/query.js index 036f0d5f98c..ff922c77577 100644 --- a/lib/query.js +++ b/lib/query.js @@ -1618,10 +1618,6 @@ Query.prototype.setOptions = function(options, overwrite) { this._mongooseOptions.sanitizeFilter = options.sanitizeFilter; delete options.sanitizeFilter; } - if ('overwrite' in options) { - this._mongooseOptions.overwrite = options.overwrite; - delete options.overwrite; - } if ('timestamps' in options) { this._mongooseOptions.timestamps = options.timestamps; delete options.timestamps; @@ -1888,11 +1884,6 @@ Query.prototype._updateForExec = function() { while (i--) { const op = ops[i]; - if (this._mongooseOptions.overwrite) { - ret[op] = update[op]; - continue; - } - if ('$' !== op[0]) { // fix up $set sugar if (!ret.$set) { @@ -3267,7 +3258,7 @@ Query.prototype._findOneAndUpdate = async function _findOneAndUpdate() { convertNewToReturnDocument(options); this._applyTranslateAliases(options); - this._update = this._castUpdate(this._update, false); + this._update = this._castUpdate(this._update); const _opts = Object.assign({}, options, { setDefaultsOnInsert: this._mongooseOptions.setDefaultsOnInsert @@ -3738,7 +3729,7 @@ async function _updateThunk(op) { if (isOverwriting) { this._update = new this.model(this._update, null, true); } else { - this._update = this._castUpdate(this._update, this._mongooseOptions.overwrite); + this._update = this._castUpdate(this._update); if (this._update == null || Object.keys(this._update).length === 0) { return { acknowledged: false }; @@ -4536,7 +4527,6 @@ Query.prototype.post = function(fn) { * Casts obj for an update command. * * @param {Object} obj - * @param {Boolean} overwrite * @return {Object} obj after casting its values * @method _castUpdate * @memberOf Query diff --git a/test/model.updateOne.test.js b/test/model.updateOne.test.js index 138b2ce43cb..da18c7ceb47 100644 --- a/test/model.updateOne.test.js +++ b/test/model.updateOne.test.js @@ -874,22 +874,6 @@ describe('model: updateOne:', function() { }); }); - it('works with $set and overwrite (gh-2515)', async function() { - const schema = new Schema({ breakfast: String }); - const M = db.model('Test', schema); - - let doc = await M.create({ breakfast: 'bacon' }); - await M.updateOne( - { _id: doc._id }, - { $set: { breakfast: 'eggs' } }, - { overwrite: true } - ); - - doc = await M.findOne({ _id: doc._id }); - assert.equal(doc.breakfast, 'eggs'); - - }); - it('successfully casts set with nested mixed objects (gh-2796)', async function() { const schema = new Schema({ breakfast: {} }); const M = db.model('Test', schema); @@ -1246,33 +1230,6 @@ describe('model: updateOne:', function() { assert.equal(doc.name, 'Val'); }); - it('casting $push with overwrite (gh-3564)', async function() { - const schema = mongoose.Schema({ - topicId: Number, - name: String, - followers: [Number] - }); - - let doc = { - topicId: 100, - name: 'name', - followers: [500] - }; - - const M = db.model('Test', schema); - - await M.create(doc); - - const update = { $push: { followers: 200 } }; - const opts = { overwrite: true, new: true, upsert: false, multi: false }; - - await M.updateOne({ topicId: doc.topicId }, update, opts); - doc = await M.findOne({ topicId: doc.topicId }); - assert.equal(doc.name, 'name'); - assert.deepEqual(doc.followers.toObject(), [500, 200]); - - }); - it('$push with buffer doesnt throw error (gh-3890)', async function() { const InfoSchema = new Schema({ prop: { type: Buffer } @@ -1747,31 +1704,6 @@ describe('model: updateOne:', function() { assert.deepEqual(doc.profiles[0], { rules: {} }); }); - it('with overwrite and upsert (gh-4749) (gh-5631)', function() { - const schema = new Schema({ - name: String, - meta: { age: { type: Number } } - }); - const User = db.model('User', schema); - - const filter = { name: 'Bar' }; - const update = { name: 'Bar', meta: { age: 33 } }; - const options = { overwrite: true, upsert: true }; - const q2 = User.updateOne(filter, update, options); - assert.deepEqual(q2.getUpdate(), { - __v: 0, - meta: { age: 33 }, - name: 'Bar' - }); - - const q3 = User.findOneAndUpdate(filter, update, options); - assert.deepEqual(q3.getUpdate(), { - __v: 0, - meta: { age: 33 }, - name: 'Bar' - }); - }); - it('findOneAndUpdate with nested arrays (gh-5032)', async function() { const schema = Schema({ name: String, From d6cd1db6311fd3b54a17f52791fcfdc700c8add8 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 19 Oct 2023 21:12:53 -0400 Subject: [PATCH 5/9] test: fix a couple of failing tests --- test/document.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/document.test.js b/test/document.test.js index 616aeb301f9..59438c61879 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -1985,7 +1985,7 @@ describe('document', function() { const err = await person.save().then(() => null, err => err); assert.equal(err instanceof DocumentNotFoundError, true); - assert.equal(err.message, `No document found for query "{ _id: new ObjectId("${person._id}") }" on model "Person"`); + assert.equal(err.message, `No document found for query "{ _id: new ObjectId('${person._id}') }" on model "Person"`); }); it('saving a document when version bump required, throws a VersionError when document is not found (gh-10974)', async function() { @@ -2020,7 +2020,7 @@ describe('document', function() { } catch (err) { assert.equal(err instanceof DocumentNotFoundError, true); - assert.equal(err.message, `No document found for query "{ _id: new ObjectId("${person._id}") }" on model "Person"`); + assert.equal(err.message, `No document found for query "{ _id: new ObjectId('${person._id}') }" on model "Person"`); threw = true; } From c7f110eaf61f1aeaa6bfcac99bd31ae1d89ddc29 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 19 Oct 2023 21:13:22 -0400 Subject: [PATCH 6/9] docs(migrating_to_8): add note about `overwrite` to migration guide --- docs/migrating_to_8.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/migrating_to_8.md b/docs/migrating_to_8.md index 459a2f64ea5..24f8c235121 100644 --- a/docs/migrating_to_8.md +++ b/docs/migrating_to_8.md @@ -20,6 +20,7 @@ If you're still on Mongoose 6.x or earlier, please read the [Mongoose 6.x to 7.x * [`null` is valid for non-required string enums](#null-is-valid-for-non-required-string-enums) * [Apply minimize when `save()` updates an existing document](#apply-minimize-when-save-updates-an-existing-document) * [Apply base schema paths before discriminator paths](#apply-base-schema-paths-before-discriminator-paths) +* [Removed `overwrite` option for `findOneAndUpdate()`](#removed-overwrite-option-for-findoneandupdate) * [Changed behavior for `findOneAndUpdate()` with `orFail()` and upsert](#changed-behavior-for-findoneandupdate-with-orfail-and-upsert) * [`create()` waits until all saves are done before throwing any error](#create-waits-until-all-saves-are-done-before-throwing-any-error) * [`Model.validate()` returns copy of object](#model-validate-returns-copy-of-object) @@ -165,6 +166,15 @@ const doc = new D({ name: 'test', otherProp: 'test' }); console.log(doc.toObject({ getters: true })); ``` +

Removed overwrite option for findOneAndUpdate()

+ +Mongoose 7 and earlier supported an `overwrite` option for `findOneAndUpdate()`, `updateOne()`, and `update()`. +Before Mongoose 7, `overwrite` would skip wrapping the `update` parameter in `$set`, which meant that `findOneAndUpdate()` and `update()` would overwrite the matched document. +In Mongoose 7, setting `overwrite` would convert `findOneAndUpdate()` to `findOneAndReplace()` and `updateOne()` to `replaceOne()` to retain backwards compatibility. + +In Mongoose 8, the `overwrite` option is no longer supported. +If you want to overwrite the entire document, use `findOneAndReplace()` or `replaceOne()`. +

Changed behavior for findOneAndUpdate() with orFail() and upsert

In Mongoose 7, `findOneAndUpdate(filter, update, { upsert: true }).orFail()` would throw a `DocumentNotFoundError` if a new document was upserted. From 8fe5c3611517d10f8774787ed10498346dc8516b Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 19 Oct 2023 21:18:47 -0400 Subject: [PATCH 7/9] docs: fix lint --- docs/migrating_to_8.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/migrating_to_8.md b/docs/migrating_to_8.md index 24f8c235121..1b014eeef54 100644 --- a/docs/migrating_to_8.md +++ b/docs/migrating_to_8.md @@ -134,8 +134,8 @@ rawDoc.nested; // undefined in Mongoose 8, {} in Mongoose 7

Apply base schema paths before discriminator paths

-This means that, in Mongoose 8, getters and setters on discriminator paths run _after_ getters and setters on base paths. -In Mongoose 7, getters and setters on discriminator paths ran _before_ getters and setters on base paths. +This means that, in Mongoose 8, getters and setters on discriminator paths run *after* getters and setters on base paths. +In Mongoose 7, getters and setters on discriminator paths ran *before* getters and setters on base paths. ```javascript @@ -263,4 +263,5 @@ const schema = new Schema({ // Works in Mongoose 8. Compile error in Mongoose 7. const names: string[] = await MyModel.distinct('name'); -``` \ No newline at end of file +``` + From ce66e235cddda5bfd96c4e0c4043620cb733c49a Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 19 Oct 2023 21:23:41 -0400 Subject: [PATCH 8/9] fix lint --- docs/migrating_to_8.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/migrating_to_8.md b/docs/migrating_to_8.md index 1b014eeef54..40383e6517f 100644 --- a/docs/migrating_to_8.md +++ b/docs/migrating_to_8.md @@ -264,4 +264,3 @@ const schema = new Schema({ // Works in Mongoose 8. Compile error in Mongoose 7. const names: string[] = await MyModel.distinct('name'); ``` - From 30888e392c3a9f5fd0c9374a3290db7002db257f Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 19 Oct 2023 21:33:31 -0400 Subject: [PATCH 9/9] test: fix typescript tests --- test/types/maps.test.ts | 2 +- test/types/models.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/types/maps.test.ts b/test/types/maps.test.ts index 496a7072830..69cd016c74f 100644 --- a/test/types/maps.test.ts +++ b/test/types/maps.test.ts @@ -83,5 +83,5 @@ function gh13755() { const TestModel = model('Test', testSchema); const doc = new TestModel(); - expectType | undefined>(doc.instance); + expectType | undefined | null>(doc.instance); } diff --git a/test/types/models.test.ts b/test/types/models.test.ts index e28bb930500..c4eef2bf0c3 100644 --- a/test/types/models.test.ts +++ b/test/types/models.test.ts @@ -744,9 +744,9 @@ function gh13957() { } interface ITest { - name?: string + name: string } - const schema = new Schema({ name: String }); + const schema = new Schema({ name: { type: String, required: true } }); const TestModel = model('Test', schema); const repository = new RepositoryBase(TestModel); expectType>(repository.insertMany([{ name: 'test' }]));