问题:
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!