diff --git a/lib/schema.js b/lib/schema.js index 6f25a00ccbe..48ca4365bfd 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -2288,28 +2288,30 @@ Schema.prototype.virtual = function(name, options) { virtual.options = options; virtual. - set(function(_v) { + set(function(v) { if (!this.$$populatedVirtuals) { this.$$populatedVirtuals = {}; } if (options.justOne || options.count) { - this.$$populatedVirtuals[name] = Array.isArray(_v) ? - _v[0] : - _v; + this.$$populatedVirtuals[name] = Array.isArray(v) ? + v[0] : + v; if (typeof this.$$populatedVirtuals[name] !== 'object') { - this.$$populatedVirtuals[name] = options.count ? _v : null; + this.$$populatedVirtuals[name] = options.count ? v : null; } } else { - this.$$populatedVirtuals[name] = Array.isArray(_v) ? - _v : - _v == null ? [] : [_v]; + this.$$populatedVirtuals[name] = Array.isArray(v) ? + v : + v == null ? [] : [v]; this.$$populatedVirtuals[name] = this.$$populatedVirtuals[name].filter(function(doc) { return doc && typeof doc === 'object'; }); } + + return this.$$populatedVirtuals[name]; }); if (typeof options.get === 'function') { diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 0a74994be3a..2252265cb8a 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -10868,4 +10868,58 @@ describe('model: populate:', function() { { name: 'foo', prop: 'bar' } ); }); + + it('calls setter on virtual populated path with populated doc (gh-14285)', async function() { + const userSchema = new Schema({ + email: String, + name: 'String' + }); + + const User = db.model('User', userSchema); + + const user = await User.create({ + email: 'admin@example.com', + name: 'Admin' + }); + + const personSchema = new Schema({ + userId: ObjectId, + userType: String + }); + + personSchema. + virtual('user', { + ref() { + return this.userType; + }, + localField: 'userId', + foreignField: '_id', + justOne: true + }). + set(function(user) { + if (user) { + this.userId = user._id; + this.userType = user.constructor.modelName; + } else { + this.userId = null; + this.userType = null; + } + + return user; + }); + + const Person = db.model('Person', personSchema); + + const person = new Person({ + userId: user._id, + userType: 'User' + }); + + await person.save(); + + const personFromDb = await Person.findById(person._id).populate('user'); + assert.equal(personFromDb.user.name, 'Admin'); + assert.equal(personFromDb.userType, 'User'); + assert.equal(personFromDb.userId.toHexString(), user._id.toHexString()); + }); });