mongoose
mongoose copied to clipboard
virtual populate that relies on another virtual doesn't return populated values
userSchema ({
profile: { type: String, default: ''}
})
companySchema ({
name: {type: String}
})
companyUserSchema ({
_company: {type: Schema.Types.ObjectId, ref: 'Company'},
_user: {type: Schema.Types.ObjectId, ref: 'User'},
_team_members: [{type: Schema.Types.ObjectId, ref: 'User'}]
})
userSchema.virtual('_company_user', {
ref: 'CompanyUser',
localField: '_id',
foreignField: '_user'
})
userSchema.virtual('team_members', {
ref: 'User',
localField: '_company_user._team_members'
foreignField: '_id'
})
user.team_members returns an array of ObjectIds unpopulated.
user
{
profile: 'profile1',
_company_user: {
_company: <unpopulated random hash>
_user: <random hash>
_team_members: [<unpopulated random hash>]
},
team_members: [<unpopulated random hash>] //i was expecting this to be populated
}
Thanks for reporting, will investigate ASAP
We currently don't support this, will add for a future release. As a workaround, you need to use deep populate
const assert = require('assert');
const mongoose = require('mongoose');
mongoose.set('debug', true);
const GITHUB_ISSUE = `gh6678`;
const connectionString = `mongodb://localhost:27017/${ GITHUB_ISSUE }`;
const { Schema } = mongoose;
run().then(() => console.log('done')).catch(error => console.error(error.stack));
async function run() {
await mongoose.connect(connectionString);
await mongoose.connection.dropDatabase();
const userSchema = new mongoose.Schema({
profile: { type: String, default: ''}
});
const companySchema = new mongoose.Schema({
name: {type: String}
});
const companyUserSchema = new mongoose.Schema({
_company: {type: Schema.Types.ObjectId, ref: 'Company'},
_user: {type: Schema.Types.ObjectId, ref: 'User'},
_team_members: [{type: Schema.Types.ObjectId, ref: 'User'}]
});
companyUserSchema.virtual('team_members', {
ref: 'User',
localField: '_team_members',
foreignField: '_id'
});
userSchema.virtual('_company_user', {
ref: 'CompanyUser',
localField: '_id',
foreignField: '_user'
});
const Company = mongoose.model('Company', companySchema);
const User = mongoose.model('User', userSchema);
const CompanyUser = mongoose.model('CompanyUser', companyUserSchema);
const company = await Company.create({ name: 'Acme' });
const user = await User.create({ profile: 'foo' });
const mapping = await CompanyUser.create({ _company: company._id, _user: user._id, _team_members: [user._id] });
//const doc = await User.findOne().populate('_company_user team_members');
const doc = await User.findOne().populate({
path: '_company_user',
populate: { path: 'team_members' }
});
console.log(require('util').inspect(doc.toObject({ virtuals: true }), { depth: 10 }));
}
when the feature will rollout?
@SwapnilSoni1999 we don't have a plan to support this currently. There's a straightforward workaround so this isn't a priority.
const doc = await User.findOne().populate({ path: '_company_user', populate: { path: 'team_members' } });
Am just curious why in the deep nested populate, you did {...,populate: { path: 'team_members' } rather than {...,populate: { path: '_team_members' } , with the _team_members just coming directly from the CompanyUser model field