diff --git a/lib/helpers/populate/assignVals.js b/lib/helpers/populate/assignVals.js index 44de64fbc39..8f363988f87 100644 --- a/lib/helpers/populate/assignVals.js +++ b/lib/helpers/populate/assignVals.js @@ -101,8 +101,8 @@ module.exports = function assignVals(o) { valueToSet = numDocs(rawIds[i]); } else if (Array.isArray(o.match)) { valueToSet = Array.isArray(rawIds[i]) ? - rawIds[i].filter(sift(o.match[i])) : - [rawIds[i]].filter(sift(o.match[i]))[0]; + rawIds[i].filter(v => v == null || sift(o.match[i])(v)) : + [rawIds[i]].filter(v => v == null || sift(o.match[i])(v))[0]; } else { valueToSet = rawIds[i]; } diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 1c6029853de..148093e5d67 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10859,4 +10859,57 @@ describe('model: populate:', function() { { name: 'foo', prop: 'bar' } ); }); + + it('avoids filtering out `null` values when applying match function (gh-14494)', async function() { + const gradeSchema = new mongoose.Schema({ + studentId: mongoose.Types.ObjectId, + classId: mongoose.Types.ObjectId, + grade: String + }); + + const Grade = db.model('Test', gradeSchema); + + const studentSchema = new mongoose.Schema({ + name: String + }); + + studentSchema.virtual('grade', { + ref: Grade, + localField: '_id', + foreignField: 'studentId', + match: (doc) => ({ + classId: doc._id + }), + justOne: true + }); + + const classSchema = new mongoose.Schema({ + name: String, + students: [studentSchema] + }); + + const Class = db.model('Test2', classSchema); + + const newClass = await Class.create({ + name: 'History', + students: [{ name: 'Henry' }, { name: 'Robert' }] + }); + + const studentRobert = newClass.students.find( + ({ name }) => name === 'Robert' + ); + + await Grade.create({ + studentId: studentRobert._id, + classId: newClass._id, + grade: 'B' + }); + + const latestClass = await Class.findOne({ name: 'History' }).populate('students.grade'); + + assert.equal(latestClass.students[0].name, 'Henry'); + assert.equal(latestClass.students[0].grade, null); + assert.equal(latestClass.students[1].name, 'Robert'); + assert.equal(latestClass.students[1].grade.grade, 'B'); + }); });