猫鼬-无法读取未定义的属性“ push”

时间:2019-02-22 18:36:29

标签: javascript node.js mongoose

我想向博客Web应用程序添加评论功能。我目前有一篇文章,或者我称之为“采访”模式,如下所示:

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});

它包含一个注释数组,这些注释引用了我创建的注释模型:

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});

在路由器中,我有一个post方法可以对特定文章发表评论:

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);
});

当我向邮递员发送此端点请求时,收到以下错误消息:

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

在我的post方法中引用以下行: req.interview.comments.push(comment);

我似乎无法弄清楚为什么收到此错误消息。任何建议或反馈表示赞赏!

2 个答案:

答案 0 :(得分:1)

由于req.interview.commentsundefined而产生此错误。请注意,req.interview已定义,否则您将得到无法读取未定义属性'comments'错误。

根据提供的代码,看起来您正在使用express,req.interview很可能是使用app.param() middleware初始化的。

请尝试在代码中找到app.param('interview', function(...)),然后仔细检查如何使用该方法解决面试。很可能是简单的Interview.findById调用。

在这种情况下,应通过在中间件中添加以下行来解决此问题:

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

否则,您可以修补路由处理程序:

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

这应该可以解决您的问题。

中间件极有可能不是注入猫鼬模型实例,而是注入其他东西,在这种情况下,您将通过从db获取模型来解决问题:

Interview.findById(req.params.interview);

请注意,req.params用于获取采访ID。


非常有趣的是,如何将interview.comments设置为undefined。像这样初始化面试模型时:

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

猫鼬将为注释属性创建并保留一个空数组。因此,可以使用显式设置为comments的{​​{1}}来初始化和持久化代码访问中的某个地方,或者正在修改数据库对象。


更新:

再三考虑,此错误的根本原因很可能是由于缺少数据库迁移。

  

我想向博客Web应用程序添加评论功能。

更改模型架构时,猫鼬不会自动修补现有的数据库集合。因此,在您将undefined属性引入comments模型之后,猫鼬会使用已初始化的interview属性来保留所有新的采访。

但是当您访问在此更改之前创建的采访时,comments属性将丢失,从而导致此特定错误。

因此,另一种解决方案是迁移现有的db数据,例如:

comments

这样,您的所有数据将保持一致。尽管有some tools个可用于编写迁移的文件,但对于这种特定情况,它们可能会有些过分。

答案 1 :(得分:0)

首先,您得到的错误是因为req.interview.comments未定义。您期望它是一个数组吗?

这里的问题是,您在哪里定义req.interview.comments?根据您向我显示的请求,请求中实际上应该只定义了两件事:req.params.interview(这是采访的ID)和req.body.comment。长话短说,req.interview.comments是不确定的。

要解决此问题,您首先需要使用在请求参数中获得的采访ID从数据库中查找采访文档。一旦找到,就可以继续...

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);
});

我稍微修改了您的代码。并非100%肯定它是准确的,但我相信您会明白。希望这会有所帮助!