From fbc01b8a53a039e08142660379819a86101ca560 Mon Sep 17 00:00:00 2001 From: Zurab Sabakhtarishvili Date: Fri, 8 Sep 2023 00:04:26 -0500 Subject: [PATCH 1/3] Fixed exception where a null element within an array would be attempted to be populated. Prior to this change, if there was a wild NULL object in an array within a document, mongoose would attempt to populate it, and would crash. For example, if we had a schema containing founders array in such a way - founders: [ { legal_form: { type: mongoose.Schema.Types.ObjectId, ref: "Legal_Form" }, name: String, identification_code: String, ownership_percentage: Number, }, ], and our database contained a document with founders looking like following - [ { name: ''name", identification_code: ''id_code", ownership_percentage: 51.5, _id: new ObjectId("63e1fc49d4ff7ce99a3a3faf") }, null ] Then following error would be thrown - TypeError: Cannot read properties of null (reading 'populated') --- lib/helpers/populate/markArraySubdocsPopulated.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/helpers/populate/markArraySubdocsPopulated.js b/lib/helpers/populate/markArraySubdocsPopulated.js index 28b19a1989a..a22605a1d78 100644 --- a/lib/helpers/populate/markArraySubdocsPopulated.js +++ b/lib/helpers/populate/markArraySubdocsPopulated.js @@ -38,7 +38,9 @@ module.exports = function markArraySubdocsPopulated(doc, populated) { if (utils.isMongooseDocumentArray(val)) { for (let j = 0; j < val.length; ++j) { - val[j].populated(rest, item._docs[id] == null ? void 0 : item._docs[id][j], item); + if(val[j]){ + val[j].populated(rest, item._docs[id] == null ? void 0 : item._docs[id][j], item); + } } break; } From 78bca702fa3dc6b59086fef8d9aed2ca570ee448 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 8 Sep 2023 09:56:40 -0400 Subject: [PATCH 2/3] test: add test case for #13839 --- .../populate/markArraySubdocsPopulated.js | 2 +- test/model.populate.test.js | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/helpers/populate/markArraySubdocsPopulated.js b/lib/helpers/populate/markArraySubdocsPopulated.js index a22605a1d78..f9cc83cb6bf 100644 --- a/lib/helpers/populate/markArraySubdocsPopulated.js +++ b/lib/helpers/populate/markArraySubdocsPopulated.js @@ -38,7 +38,7 @@ module.exports = function markArraySubdocsPopulated(doc, populated) { if (utils.isMongooseDocumentArray(val)) { for (let j = 0; j < val.length; ++j) { - if(val[j]){ + if (val[j]) { val[j].populated(rest, item._docs[id] == null ? void 0 : item._docs[id][j], item); } } diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 690e7783872..bd79133c9a1 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10285,6 +10285,28 @@ describe('model: populate:', function() { }); + it('handles populating underneath document arrays that have null (gh-13839)', async function() { + const schema = new Schema({ + children: [ + { + doc: { type: mongoose.Schema.Types.ObjectId, ref: 'Child' }, + name: String + }, + ] + }); + const Parent = db.model('Parent', schema); + const Child = db.model('Child', new Schema({ name: String })); + + const child = new Child({ name: 'gh-13839-test' }); + await child.save(); + let parent = new Parent({ children: [{ doc: child._id, name: 'foo' }, null] }); + await parent.save(); + + parent = await Parent.findById(parent._id).populate('children.doc'); + assert.equal(parent.children.length, 2); + assert.equal(parent.children[0].doc.name, 'gh-13839-test'); + assert.equal(parent.children[1], null); + }); describe('strictPopulate', function() { it('reports full path when throwing `strictPopulate` error with deep populate (gh-10923)', async function() { From e42aaafc4d2f00861434219e152478512a2b006a Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 8 Sep 2023 10:36:04 -0400 Subject: [PATCH 3/3] style: fix lint --- test/model.populate.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/model.populate.test.js b/test/model.populate.test.js index bd79133c9a1..c1007f69315 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10291,8 +10291,8 @@ describe('model: populate:', function() { { doc: { type: mongoose.Schema.Types.ObjectId, ref: 'Child' }, name: String - }, - ] + } + ] }); const Parent = db.model('Parent', schema); const Child = db.model('Child', new Schema({ name: String }));