Mongoose - Cannot read property 'push' of undefined

问题: I would like to add commenting functionality to a blog web app. I currently have an article or as I call it "interview" schema as follows: var InterviewSchema = new mongo...

问题:

I would like to add commenting functionality to a blog web app. I currently have an article or as I call it "interview" schema as follows:

var InterviewSchema = new mongoose.Schema({
  slug: {type: String, lowercase: true, unique:true},
  title: String,
  description: String,
  body: String,
  favoritesCount: {type: Number, default: 0},
  tagList: [{type: String}],
  author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
  comments: [{type: mongoose.Schema.Types.ObjectId, ref: 'Comment'}]
}, {timestamps: true, usePushEach: true});

It contains an array of comments that is referenced to a comments model that I created:

var CommentSchema = new mongoose.Schema({
  body: String,
  author: {type: mongoose.Schema.Types.ObjectId, ref:'User'},
  interview: {type: mongoose.Schema.Types.ObjectId, ref:'Interview'}
}, {timestamps: true});

In my router, I have a post method to post a comment to a particular article:

router.post('/:interview/comments', auth.required, function(req, res, next){
  User.findById(req.payload.id).then(function(user) {
    if(!user) {return res.sendStatus(401); }

    var comment = new Comment(req.body.comment);
    comment.interview = req.interview;
    comment.author = user;

    return comment.save().then(function() {
      req.interview.comments.push(comment);

      return req.interview.save().then(function(article) {
        res.json({comment: comment.toJSONFor(user)});
      });
    });
  }).catch(next);
});

When I send a request this endpoint on postman I get the following error message:

{
    "errors": {
        "message": "Cannot read property 'push' of undefined",
        "error": {}
    }
}

Which is referencing the following line in my post method: req.interview.comments.push(comment);

I can't seem to figure out why I'm getting this error message. Any suggestions or feedback is appreciated!


回答1:

This error is generated because req.interview.comments is undefined. Note, that req.interview is defined, otherwise you would get Cannot read property 'comments' of undefined error.

According to code you are provided, looks like you are using express and req.interview is most probably initialized using app.param() middleware.

Please, try find app.param('interview', function(...)) in your code and double check how interview is resolved in that method. Most probably it is simple Interview.findById invocation.

If this is the case, the issue should be resolved by adding this line to your middleware:

interview.comments = interview.comments || [];

Otherwise you can patch route handler:

interview.comments = interview.comments || [];
req.interview.comments.push(comment);

This should solve your problem.

There is slight possibility that middleware is injecting not a mongoose model instance, but something else, in this case, you will solve your problem by fetching model from db instead:

Interview.findById(req.params.interview);

Note, req.params is used to get interview id.


It is quite interesting, how you got your interview.comments set as undefined. When initializing interview model like this:

new Interview({ author: user, title: 'Demo Interview' }).save()

Mongoose will create and persist an empty array for comments property. So either somewhere in your code interview can be initialized and persisted with comments explicitly set as undefined or something else is modifying your db objects.


Update:

On the second thought, the root cause of this error is most probably due to lack of db migrations.

I would like to add commenting functionality to a blog web app.

When you change model schema, mongoose won't automatically patch your existing db collection. So after you introduced comments property to interview model, all new interviews will be persisted by mongoose with initialized comments property.

But when you access interviews that were created before this change, comments property will be missing, resulting this specific error.

So another solution would be to migrate exiting db data, for example like this:

db.getCollection('interviews').updateMany({ comments: null }, { $set: { comments: [] }})

This way all your data will be consistent. Although there are some tools available for writing migrations, they might be a little overkill for this specific case.


回答2:

So first things first, the error you are getting is because req.interview.comments is undefined. You're expecting it to be an array right?

Well the question here is, where do you define req.interview.comments? Based on the request that you showed me, there should really only be two things defined in the request, req.params.interview (which is the id of the interview) and req.body.comment. So long story short, req.interview.comments is undefined.

To fix this, you will first need to use that interview ID you got in your request params to find the interview document from the database. Once you find that, you can then proceed...

router.post('/:interview/comments', auth.required, function(req, res, next){
  User.findById(req.payload.id).then(function(user) {
    if(!user) {return res.sendStatus(401); }

    return Interview.find({ _id: req.params.interview });
  })
  .then(function(interview) {


    var comment = new Comment(req.body.comment);
    comment.interview = req.params.interview;
    comment.author = user;

    return comment.save().then(function() {
     // We are using the interview found from DB 
     interview.comments.push(comment);

      return interview.save().then(function(article) {
        res.json({comment: comment.toJSONFor(user)});
      });
    });
  }).catch(next);
});

I modified your code a bit. Not 100% sure it's accurate, but I believe you get the idea. Hope this helps!

  • 发表于 2019-02-24 12:39
  • 阅读 ( 1071 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除