Reputation: 882
I have an app with express and mongoose. I have two schemas, a Blog schema and a Comment schema. I want to push a comment array from a form to a single blog, using RESTful routes. If I embed Comment schema in Blog schema it works, on the other hand if I reference the ObjectId of the Comment schema inside the Blog schema the code works for the first comment, then at the second one, the console throw a Validation Error:
(node:5472) UnhandledPromiseRejectionWarning:
Unhandled promise rejection (rejection id: 1):
ValidationError: Blog validation failed:
comments: Cast to [undefined] failed for value
"[{
"_id":"5a57374da3ba43156005c881",
"text":"test1",
"author":"test1",
"__v":0
}]"
at path "comments"
the object logged is the first comment I pushed to array
This is the Blog schema (embed version):
//Embed
var mongoose = require("mongoose");
var comment = new mongoose.Schema({
text: String,
author: String
});
var blogSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
comments: [comment]
});
module.exports = mongoose.model("Blog", blogSchema);
This is the Blog schema (reference version):
// Reference
var mongoose = require("mongoose");
var blogSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}]
});
module.exports = mongoose.model("Blog", blogSchema);
And this is the Comment Schema:
var mongoose = require("mongoose");
var commentSchema = new mongoose.Schema({
text: String,
author: String
});
module.exports = mongoose.model("Comment", commentSchema);
This is the Comment route I use to post new comment:
app.post("/blogs/:id/comments", function (req, res) {
// find the correct campground
Blog.findById(req.params.id, function (err, blog) {
if (err) {
console.log(err);
res.redirect("/blogs");
} else {
Comment.create(req.body.comment, function (err, comment) {
if (err) {
console.log(err);
} else {
blog.comments.push(comment);
blog.save();
res.redirect("/blogs/" + blog._id);
}
});
}
});
});
Note that the Route works correctly and redirect to the "blogs/:id" page, if I console.log the blog or che comment object I have the correct output
At last, this is the form I use to post request:
<div class="container">
<div class="row">
<h1 style="text-align: center;">Add a new Comment to <%= blog.name %></h1>
<div style="width: 30%; margin:25px auto;">
<form action="/blog/<%= blog._id %>/comments" method="POST">
<div class="form-group">
<input class="form-control" type="text" name="comment[text]" placeholder="text">
</div>
<div class="form-group">
<input class="form-control" type="text" name="comment[author]" placeholder="author">
</div>
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">Submit!</button>
</div>
</form>
<a href="/blogs">Go Back</a>
</div>
</div>
</div>
EDIT I would prefer to use only the Ids of the comment instead of the full comment schema, but I don't know how to set the application up to do that.
Same error is reported on mongoose github profile too: https://github.com/Automattic/mongoose/issues/5972
Upvotes: 0
Views: 902
Reputation: 882
The Only way I found to solve this problem is refactor my code to look like this:
app.post("/blogs/:id/comments", function (req, res) {
Comment.create(req.body.comment, function (err, comment) {
if (err) {
console.log(err);
} else {
Blog.findOne({"_id": req.params.id})
.populate("comments")
.exec(function (err, blog) {
if (err) {
console.log(err);
res.redirect("/blogs");
} else {
blog.comments.push(comment);
blog.save();
res.redirect("/blogs/" + blog._id);
}
});
}
});
});
However this not explain the behavior of the Schemas
Hope it helps
Upvotes: 0
Reputation: 238
For Reference version: After creating comment you can simply push id of created comment doc in blog document.
blog.comments.push(comment._id);
or
blog.comments.push(mongoose.Types.ObjectId(comment._id)); //to ensure the pushed id will be mongoose object id.
You must require mongoose for the step 2.
Upvotes: 0