From 49aa88dd3eb7a01c95eeb453a9bbf3978cc6a8de Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 16 Jul 2022 10:56:04 +0200 Subject: [PATCH] fix: mongoose schema default should not mutate original object Closes #12102 --- lib/document.js | 6 ++++-- test/document.test.js | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/lib/document.js b/lib/document.js index 72c12c75442..4f525addcc2 100644 --- a/lib/document.js +++ b/lib/document.js @@ -1149,8 +1149,10 @@ Document.prototype.$set = function $set(path, val, type, options) { } if (utils.isNonBuiltinObject(valForKey) && pathtype === 'nested') { - $applyDefaultsToNested(path[key], prefix + key, this); - this.$set(prefix + key, path[key], constructing, Object.assign({}, options, { _skipMarkModified: true })); + // Create a copy of the object to avoid editing the original + const pathKey = { ...path[key] } + $applyDefaultsToNested(pathKey, prefix + key, this); + this.$set(prefix + key, pathKey, constructing, Object.assign({}, options, { _skipMarkModified: true })); continue; } else if (strict) { // Don't overwrite defaults with undefined keys (gh-3981) (gh-9039) diff --git a/test/document.test.js b/test/document.test.js index 160b14fbe3d..1ccc39bd19f 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -2332,6 +2332,31 @@ describe('document', function() { assert.equal(res.test, 'test'); assert.ok(!res.subDoc); }); + + it('original object nested fields should not be mutated by mongoose schema defaults (gh-12102)', function() { + const schema = new mongoose.Schema({ + topLevelField1: { + nestedField1: String, + nestedField2: {type: String, default: 'defValue'} + }, + topLevelField2: {type: String, default: 'defValue'} + }) + + const Model = db.model('Test', schema); + + const originalData = { + topLevelField1: { + nestedField1: 'provided' + } + } + + const model = new Model(originalData); + assert.deepEqual(originalData, { + topLevelField1: { + nestedField1: 'provided' + } + }) + }); }); describe('error processing (gh-2284)', async function() {