From da04458f9ed60bfa5c563dfd57150067275e7096 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 6 Mar 2023 11:41:44 -0500 Subject: [PATCH 1/4] fix(document): avoid setting array default if document array projected out by sibling projection Fix #13003 --- lib/helpers/document/applyDefaults.js | 2 +- test/docs/debug.test.js | 7 ++++++- test/document.test.js | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/helpers/document/applyDefaults.js b/lib/helpers/document/applyDefaults.js index 88cef3924f8..10a4e1ffefd 100644 --- a/lib/helpers/document/applyDefaults.js +++ b/lib/helpers/document/applyDefaults.js @@ -32,7 +32,7 @@ module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildre } } else if (exclude === false && fields && !included) { const hasSubpaths = type.$isSingleNested || type.$isMongooseDocumentArray; - if (curPath in fields || (hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[curPath])) { + if (curPath in fields || (j === len - 1 && hasSubpaths && hasIncludedChildren != null && hasIncludedChildren[curPath])) { included = true; } else if (hasIncludedChildren != null && !hasIncludedChildren[curPath]) { break; diff --git a/test/docs/debug.test.js b/test/docs/debug.test.js index b03524d8f49..4ac7b520421 100644 --- a/test/docs/debug.test.js +++ b/test/docs/debug.test.js @@ -93,10 +93,15 @@ describe('debug: shell', function() { }); it('should avoid sending null session option with document ops (gh-13052)', async function() { + const m = new mongoose.Mongoose(); + m.set('debug', true); + await m.connect(start.uri); const schema = new Schema({ name: String }); - const Test = db.model('gh_13052', schema); + const Test = m.model('gh_13052', schema); await Test.create({ name: 'foo' }); assert.equal(false, lastLog.includes('session')); + + await m.disconnect(); }); }); diff --git a/test/document.test.js b/test/document.test.js index a8fe981e1fc..144217868e1 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -12162,6 +12162,23 @@ describe('document', function() { { $pop: { arr: -1 }, $inc: { __v: 1 } } ); }); + + it('avoids setting array default if document array projected out by sibling projection (gh-13003)', async function() { + const schema = new mongoose.Schema({ + name: String, + arr: [String], + properties: { + foo: String, + bar: [{ baz: String, qux: Boolean }], + baz: String + } + }); + const Test = db.model('Test', schema); + + const doc = new Test({}, { 'properties.foo': 1 }); + doc.init({ properties: { foo: 'foo' } }); + assert.strictEqual(doc.properties.bar, undefined); + }); }); describe('Check if instance function that is supplied in schema option is availabe', function() { From 5af7c8c7ce4040fea42a546a1a2cfaae3d5dfdd9 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 6 Mar 2023 12:13:12 -0500 Subject: [PATCH 2/4] test: add test coverage for #13043 to show that issue is fixed by #13003 fix --- test/document.test.js | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/document.test.js b/test/document.test.js index 144217868e1..e8e825b4ef0 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -12179,6 +12179,47 @@ describe('document', function() { doc.init({ properties: { foo: 'foo' } }); assert.strictEqual(doc.properties.bar, undefined); }); + + it('avoids overwriting array with sibling projection (gh-13043)', async function() { + const testSchema = new mongoose.Schema({ + str: 'string', + obj: { + subObj: { + str: 'string' + }, + subArr: [{ + str: 'string' + }] + }, + arr: [{ + str: 'string' + }] + }); + const Test = db.model('Test', testSchema); + // Create one test document : obj.subArr[0].str === 'subArr.test1' + await Test.create({ + str: 'test1', + obj: { + subObj: { + str: 'subObj.test1' + }, + subArr: [{ + str: 'subArr.test1' + }] + }, + arr: [{ str: 'arr.test1' }] + }); + + const test = await Test.findOne({ str: 'test1' }, 'str obj.subObj'); + + // Update one property + test.str = test.str + ' - updated'; + await test.save(); + + const fromDb = await Test.findById(test); + assert.equal(fromDb.obj.subArr.length, 1); + assert.equal(fromDb.obj.subArr[0].str, 'subArr.test1'); + }); }); describe('Check if instance function that is supplied in schema option is availabe', function() { From c45f67d42048b723a89ae4cacb57c419ce4ca6e3 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 6 Mar 2023 13:18:46 -0500 Subject: [PATCH 3/4] test: make #13052 test consistent with others --- test/docs/debug.test.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/docs/debug.test.js b/test/docs/debug.test.js index 4ac7b520421..5c9763fb304 100644 --- a/test/docs/debug.test.js +++ b/test/docs/debug.test.js @@ -93,15 +93,11 @@ describe('debug: shell', function() { }); it('should avoid sending null session option with document ops (gh-13052)', async function() { - const m = new mongoose.Mongoose(); - m.set('debug', true); - await m.connect(start.uri); + mongoose.set('debug', { shell: false }); const schema = new Schema({ name: String }); - const Test = m.model('gh_13052', schema); + const Test = db.model('gh_13052', schema); await Test.create({ name: 'foo' }); assert.equal(false, lastLog.includes('session')); - - await m.disconnect(); }); }); From 978b49d2e63abb580d01169fe5bbee0688e112c3 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 6 Mar 2023 13:23:04 -0500 Subject: [PATCH 4/4] test: make #13052 test more explicit with debug usage --- test/docs/debug.test.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/docs/debug.test.js b/test/docs/debug.test.js index 5c9763fb304..403f2ad9dde 100644 --- a/test/docs/debug.test.js +++ b/test/docs/debug.test.js @@ -93,11 +93,20 @@ describe('debug: shell', function() { }); it('should avoid sending null session option with document ops (gh-13052)', async function() { - mongoose.set('debug', { shell: false }); + let args = []; + const m = new mongoose.Mongoose(); + m.set('debug', function() { + args.push([...arguments]); + }); + await m.connect(start.uri); const schema = new Schema({ name: String }); - const Test = db.model('gh_13052', schema); + const Test = m.model('gh_13052', schema); await Test.create({ name: 'foo' }); - assert.equal(false, lastLog.includes('session')); + assert.equal(args.length, 1); + assert.equal(args[0][1], 'insertOne'); + assert.ok(!('session' in args[0][3])); + + await m.disconnect(); }); });