From 3696a0db66251b81c255eac55f279d8abbfe42ec Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 19 Dec 2024 12:15:53 -0500 Subject: [PATCH 1/2] fix(model): handle document array paths set to non-array values in Model.castObject() Fix #15075 --- lib/model.js | 14 ++++++++++++++ test/model.test.js | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/lib/model.js b/lib/model.js index ddf149dd5d..e27cdba98d 100644 --- a/lib/model.js +++ b/lib/model.js @@ -69,6 +69,7 @@ const util = require('util'); const utils = require('./utils'); const minimize = require('./helpers/minimize'); const MongooseBulkSaveIncompleteError = require('./error/bulkSaveIncompleteError'); +const ObjectExpectedError = require('./error/objectExpected'); const modelCollectionSymbol = Symbol('mongoose#Model#collection'); const modelDbSymbol = Symbol('mongoose#Model#db'); @@ -3687,6 +3688,19 @@ Model.castObject = function castObject(obj, options) { } if (schemaType.$isMongooseDocumentArray) { + const castNonArraysOption = schemaType.options.castNonArrays != null ? schemaType.options.castNonArrays : schemaType.constructor.options.castNonArrays; + if (!Array.isArray(val)) { + if (!castNonArraysOption) { + if (!options.ignoreCastErrors) { + error = error || new ValidationError(); + error.addError(path, new ObjectExpectedError(path, val)); + } + } else { + cur[pieces[pieces.length - 1]] = [ + Model.castObject.call(schemaType.caster, val) + ]; + } + } continue; } if (schemaType.$isSingleNested || schemaType.$isMongooseDocumentArrayElement) { diff --git a/test/model.test.js b/test/model.test.js index 673834cda9..119e4d6348 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -7777,6 +7777,24 @@ describe('Model', function() { TestModel.castObject(square).shape[0], { kind: 'Square', propertyPaths: [{ property: '42' }] } ); + + const square2 = { shape: [{ kind: 'Square', propertyPaths: {} }] }; + assert.deepStrictEqual( + TestModel.castObject(square2).shape[0], + { kind: 'Square', propertyPaths: [{}] } + ); + }); + it('handles castNonArrays when document array is set to non-array value (gh-15075)', function() { + const sampleSchema = new mongoose.Schema({ + sampleArray: { + type: [new mongoose.Schema({ name: String })], + castNonArrays: false + } + }); + const Test = db.model('Test', sampleSchema); + + const obj = { sampleArray: { name: 'Taco' } }; + assert.throws(() => Test.castObject(obj), /Tried to set nested object field `sampleArray` to primitive value/); }); }); From dfd96dc4b7106bcc0192cd0037468a6a49711319 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 22 Dec 2024 14:25:01 -0500 Subject: [PATCH 2/2] Update lib/model.js Co-authored-by: Djamel Benali --- lib/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model.js b/lib/model.js index e27cdba98d..7edbce6ce2 100644 --- a/lib/model.js +++ b/lib/model.js @@ -3688,7 +3688,7 @@ Model.castObject = function castObject(obj, options) { } if (schemaType.$isMongooseDocumentArray) { - const castNonArraysOption = schemaType.options.castNonArrays != null ? schemaType.options.castNonArrays : schemaType.constructor.options.castNonArrays; + const castNonArraysOption = schemaType.options?.castNonArrays ??schemaType.constructor.options.castNonArrays; if (!Array.isArray(val)) { if (!castNonArraysOption) { if (!options.ignoreCastErrors) {