0
votes

I'm using the Mongoose 4.5 virtual populate API and am unable to get the virtual field to populate on the one side of a one-to-many.

const FilmSchema = new Schema({
  title: String,
  slug: String,
  director: String
});

const DirectorSchema = new Schema({
  name: String,
  slug: String
});

DirectorSchema.virtual('films', {
  ref: 'Film',
  localField: 'slug',
  foreignField: 'director'
});

const Film = mongoose.model('Film', FilmSchema, 'film');
const Director = mongoose.model('Director', DirectorSchema, 'director');

Director.find({}).populate('films').exec()
  .then(data => res.send(data))
  .catch(err => console.log(err));

The director data is output as expected but without any mention of films and without throwing/logging any errors.

In the query log, it looks like Mongoose is trying to do what I ask:

Mongoose: director.find({}) { fields: undefined }
Mongoose: film.find({ director: { '$in': [ 'spielberg', 'zemeckis', 'nolan' ] } }) { fields: undefined }

I've tried several variations, such as:

  • setting a ref to Director with type: String on FilmSchema.director
  • setting a ref to Director with type ObjectId on FilmSchema.director
  • replacing slug with a custom _id String

...and various combinations of the above.

I'm using the docs example and Valeri's recent article as guides.

Does anyone see what I'm doing wrong?

Versions: Node: 6.3.0 / MongoDB: 3.2.5 / Mongoose: 4.5.8

2

2 Answers

3
votes

Answered by vkarpov15 on GitHub issues:

Try res.send(data.toObject({ virtuals: true })); or setting schema.options.toJSON = { virtuals: true }. Virtuals are not included by default when you transform a mongoose doc into a pojo

1
votes

If you have set schema.options.toJSON = { virtuals: true } and are still not seeing your populated child objects, try explicitly calling .toJSON() - I was simply console.logging my objects and the data was not showing up! DOH!

ie:

const director = await Director.findOne({}).populate('films');
console.log(director);

>> { _id: 5a5f598923294f047ae2f66f, name: 'spielberg', __v: 0};

but:

const director = await Director.findOne({}).populate('films');
console.log(director.toJSON());

>> { _id: 5a5f598923294f047ae2f66f, name: 'spielberg', __v: 0,
     films: [{_id: 5a5f598923294f047ae2f6bf, title:"ET"},{_id: 5a5f598923294f047ae2f30v, title:"Jaws"}]
     };