diff --git a/lib/helpers/populate/assignVals.js b/lib/helpers/populate/assignVals.js index 017066add17..44de64fbc39 100644 --- a/lib/helpers/populate/assignVals.js +++ b/lib/helpers/populate/assignVals.js @@ -39,8 +39,10 @@ module.exports = function assignVals(o) { const options = o.options; const count = o.count && o.isVirtual; let i; + let setValueIndex = 0; function setValue(val) { + ++setValueIndex; if (count) { return val; } @@ -80,11 +82,14 @@ module.exports = function assignVals(o) { return valueFilter(val[0], options, populateOptions, _allIds); } else if (o.justOne === false && !Array.isArray(val)) { return valueFilter([val], options, populateOptions, _allIds); + } else if (o.justOne === true && !Array.isArray(val) && Array.isArray(_allIds)) { + return valueFilter(val, options, populateOptions, val == null ? val : _allIds[setValueIndex - 1]); } return valueFilter(val, options, populateOptions, _allIds); } for (i = 0; i < docs.length; ++i) { + setValueIndex = 0; const _path = o.path.endsWith('.$*') ? o.path.slice(0, -3) : o.path; const existingVal = mpath.get(_path, docs[i], lookupLocalFields); if (existingVal == null && !getVirtual(o.originalModel.schema, _path)) { diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 4e638a90178..9f629f28844 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10776,4 +10776,62 @@ describe('model: populate:', function() { new Date('2015-06-01').toString() ); }); + + it('calls transform with single ObjectId when populating justOne path underneath array (gh-14073)', async function() { + const mySchema = mongoose.Schema({ + name: { type: String }, + items: [{ + _id: false, + name: { type: String }, + brand: { type: mongoose.Schema.Types.ObjectId, ref: 'Brand' } + }] + }); + + const brandSchema = mongoose.Schema({ + name: 'String', + quantity: Number + }); + + const myModel = db.model('MyModel', mySchema); + const brandModel = db.model('Brand', brandSchema); + const { _id: id1 } = await brandModel.create({ + name: 'test', + quantity: 1 + }); + const { _id: id2 } = await brandModel.create({ + name: 'test1', + quantity: 1 + }); + const { _id: id3 } = await brandModel.create({ + name: 'test2', + quantity: 2 + }); + const brands = await brandModel.find(); + const test = new myModel({ name: 'Test Model' }); + for (let i = 0; i < brands.length; i++) { + test.items.push({ name: `${i}`, brand: brands[i]._id }); + } + + const id4 = new mongoose.Types.ObjectId(); + test.items.push({ name: '4', brand: id4 }); + await test.save(); + + const ids = []; + await myModel + .findOne() + .populate([ + { + path: 'items.brand', + transform: (doc, id) => { + ids.push(id); + return doc; + } + } + ]); + assert.equal(ids.length, 4); + assert.deepStrictEqual( + ids.map(id => id?.toHexString()), + [id1.toString(), id2.toString(), id3.toString(), id4.toString()] + ); + }); });