populate in post hook middlewhere for 'find' in mongoose

7.8k views Asked by At

I have an article schema for articles posted on my site by users. It references the Users collection:

var ArticleSchema = new Schema({
  title: { // NO MARKDOWN FOR THIS, just straight up text for separating from content
    type: String,
    required: true
  },
  author: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  }
});

I want to have a post hook on all find/findOne calls to populate the reference:

ArticleSchema.post('find', function (doc) {
  doc.populate('author');
});

For some reason, the doc that's returned in the hook does not have populate method. Do I have to populate using the ArticleSchema object instead of at the document level?

4

There are 4 answers

0
Muhammad Ghanoz Ghazali On

From MongooseJS Doc:

Query middleware differs from document middleware in a subtle but important way: in document middleware, this refers to the document being updated. In query middleware, mongoose doesn't necessarily have a reference to the document being updated, so this refers to the query object rather than the document being updated.

We cannot modify the result from inside the post find middleware as this refers to the query object.

TestSchema.post('find', function(result) {
  for (let i = 0; i < result.length; i++) {
    // it will not take any effect
    delete result[i].raw;
  }
});
0
suulisin On

The above answers may not work because they are terminating the pre hook middleware by not calling next. The right implementation should be

productSchema.pre('find', function (next) {
this.populate('category','name');
this.populate('cableType','name');
this.populate('color','names');
next();

});

0
OMAMBIA M. DAUGLOUS On

To add, the doc here is will allow your to continue to the next middleware. You can also use the following and select only some spefic fields. For instance the user model has name, email, address, and location but you only want to populate only the name and email

ArticleSchema.pre('find', function () {
    // `this` is an instance of mongoose.Query
    this.populate({path: 'author', select: '-location -address'});
});
0
Silvestre Herrera On

That's because populate is a method of the query object, not the document. You should use a pre hook instead, like so:

ArticleSchema.pre('find', function () {
    // `this` is an instance of mongoose.Query
    this.populate('author');
});