From b46848dd3b29926e878c605b3f56c71025ed1a13 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 13 Sep 2022 20:35:28 -0400 Subject: [PATCH 1/2] fix(document): correct context for default functions in subdocuments with init Fix #12328 --- lib/schema/SubdocumentPath.js | 2 +- test/document.test.js | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/schema/SubdocumentPath.js b/lib/schema/SubdocumentPath.js index 04b62cf4d19..2a477ee9262 100644 --- a/lib/schema/SubdocumentPath.js +++ b/lib/schema/SubdocumentPath.js @@ -170,7 +170,7 @@ SubdocumentPath.prototype.cast = function(val, doc, init, priorVal, options) { }, null); options = Object.assign({}, options, { priorDoc: priorVal }); if (init) { - subdoc = new Constructor(void 0, selected, doc); + subdoc = new Constructor(void 0, selected, doc, false, { defaults: false }); subdoc.$init(val); } else { if (Object.keys(val).length === 0) { diff --git a/test/document.test.js b/test/document.test.js index 9ea642d1814..d33beddfe68 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -11833,6 +11833,28 @@ describe('document', function() { assert.ok(doc.nestedPath1.mapOfSchema); }); + + it('correct context for default functions in subdocuments with init (gh-12328)', async function() { + const subSchema = new mongoose.Schema({ + propertyA: { type: String }, + propertyB: { type: String, default: function() { + return this.propertyA; + } } + }); + + const testSchema = new mongoose.Schema( + { + name: String, + sub: { type: subSchema, default: () => ({}) } + } + ); + + const Test = db.model('Test', testSchema); + + await Test.collection.insertOne({ name: 'test', sub: { propertyA: 'foo' } }); + const doc = await Test.findOne({ name: 'test' }); + assert.strictEqual(doc.sub.propertyB, 'foo'); + }); }); describe('Check if instance function that is supplied in schema option is availabe', function() { From 47ce1254abb6c88264af8e7b93f22b0dddd57b58 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 13 Sep 2022 21:33:49 -0400 Subject: [PATCH 2/2] fix: correctly apply defaults after subdoc init Fix #12328 --- lib/schema/SubdocumentPath.js | 2 ++ test/document.test.js | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/schema/SubdocumentPath.js b/lib/schema/SubdocumentPath.js index 2a477ee9262..e748d6a5026 100644 --- a/lib/schema/SubdocumentPath.js +++ b/lib/schema/SubdocumentPath.js @@ -9,6 +9,7 @@ const EventEmitter = require('events').EventEmitter; const ObjectExpectedError = require('../error/objectExpected'); const SchemaSubdocumentOptions = require('../options/SchemaSubdocumentOptions'); const SchemaType = require('../schematype'); +const applyDefaults = require('../helpers/document/applyDefaults'); const $exists = require('./operators/exists'); const castToNumber = require('./operators/helpers').castToNumber; const discriminator = require('../helpers/model/discriminator'); @@ -172,6 +173,7 @@ SubdocumentPath.prototype.cast = function(val, doc, init, priorVal, options) { if (init) { subdoc = new Constructor(void 0, selected, doc, false, { defaults: false }); subdoc.$init(val); + applyDefaults(subdoc, selected); } else { if (Object.keys(val).length === 0) { return new Constructor({}, selected, doc, undefined, options); diff --git a/test/document.test.js b/test/document.test.js index d33beddfe68..a6623d325d0 100644 --- a/test/document.test.js +++ b/test/document.test.js @@ -11835,11 +11835,17 @@ describe('document', function() { }); it('correct context for default functions in subdocuments with init (gh-12328)', async function() { + let called = 0; + const subSchema = new mongoose.Schema({ propertyA: { type: String }, - propertyB: { type: String, default: function() { - return this.propertyA; - } } + propertyB: { + type: String, + default: function() { + ++called; + return this.propertyA; + } + } }); const testSchema = new mongoose.Schema( @@ -11852,8 +11858,11 @@ describe('document', function() { const Test = db.model('Test', testSchema); await Test.collection.insertOne({ name: 'test', sub: { propertyA: 'foo' } }); + assert.strictEqual(called, 0); + const doc = await Test.findOne({ name: 'test' }); assert.strictEqual(doc.sub.propertyB, 'foo'); + assert.strictEqual(called, 1); }); });