Can anyone please help spot why the mongoose findByIdAndRemove in the delete route below...
//DELETE Route
app.delete("/blogs/:id", function(req, res){
//Destroy blog
Blog.findByIdAndRemove(req.params.id, function(err){
if(err){
res.send(err);
} else {
res.redirect("/blogs");
}
});
});
...generates the error below:
message: "Cast to ObjectId failed for value "5a6a8f967c9a190507b03433 " at path "_id" for model "Blog"",
name: "CastError",
stringValue: ""5a6a8f967c9a190507b03433 "",
kind: "ObjectId",
value: "5a6a8f967c9a190507b03433 ",
path: "_id"
Many thanks in anticipation of your help.
The problem is that you're sending a 16 character long String from the client while the method findOneByIdAndRemove demands an ObjectId. Doing this will eradicate the issue,
var mongoose = require('mongoose'); //remove it as you might already it
var ObjectId = mongoose.Types.ObjectId;
app.delete("/blogs/:id", function(req, res){
//Destroy blog
Blog.findByIdAndRemove(ObjectId(req.params.id), function(err){
if(err){
res.send(err);
} else {
res.redirect("/blogs");
}
});
});
Also, make sure that the _id is 16 character long, no spaces on either side is allowed.
Many thanks #vicbyte and Nilesh Singh for your contributions.
Indeed the code was failing due to the space at the end of the id: "5a6a8f967c9a190507b03433 ". The space came from the form issuing the DELETE:
<form id="delete" action="/blogs/<%= blog.id %> ?_method=DELETE" Method ="POST">
<button class = "ui red basic button">Delete</button>
</form>
Revising the the form as below...
<form id="delete" action="/blogs/<%= blog.id %>?_method=DELETE" Method ="POST">
<button class = "ui red basic button">Delete</button>
</form>
...cleared the error.
use async await. For Example:
async function(req,res) {
await Blog.findByIdAndRemove();
}
Related
I'm struggling to delete a row from a collection of my database using mongoose. The console said that deleting was successful (as I handled error), but when I check my database, the row is still here. I successfully add a member with a post request, but I was not able to delete it.
I suspect my route file or my hbs file.
Here is the code :
Index.js (the route part)
app.get('/delete',(req,res) => res.render('delete', {
title:'Member App',
}));
routes/members.js
// Delete member : DELETE
router.get("/delete", (req,res)=>{
console.log(req.params.id);
Member.deleteOne({ _id: req.params.id }, function(err,data) {
if (!err) {
console.log(data);
console.log("member successfully deleted")
}
else {
console.log("error")
}
});
res.redirect("/");
});
delete.hbs
<h1 class = "text-center mb-3">{{title}}</h1>
<form action="/delete" method ="DELETE" class="mb-4">
<div class="form-group">
<label for="Id">Id</label>
<input type="Id" name="Id" class ="form-control">
</div>
<input type="submit" value ="Delete member" class="btn">
</form>
The console : (it seems that the data from my callback is undefined)
Connected to mongoDB
undefined
{ n: 0, ok: 1, deletedCount: 0 }
member successfully deleted
Your input type tag is wrong.
<input type="Id" name="Id" class ="form-control">
There is no "Id" type in input (see input types values)
You don't use correct field
req.params.id
Is used, but I don't see any params in your request.
You only have the body filled with Id so in order to use it, you should call :
req.body.Id
First of all the absence of an error does not guarantee the deletion of a record in the database. So in this case prefer to use findOneAndRemove method.
Second res.redirect("/"); will called before record removing has done, so redirect should be moved into callback function like:
Member.findOneAndRemove({ _id: req.params.id }, function(err, member) {
if (!err && member) {
console.log(member);
console.log("member successfully deleted")
}
else {
console.log("error")
}
res.redirect("/");
});
I think this is related to how I've defined my schemas, but I can't seem to find where the bug is... I have an almost identical file set up that's working perfectly and I've unfortunately not been able to find a duplicate of this issue anywhere.
When sending an API request to my local Express instance via Postman, only the 'title' request body value is stored in the database. I am sending the following simple request to my route as Application/Json (thought the same happens when using x-www-form-urlencoded):
{
"postTitle": "title goes here",
"postContent": "body goes here",
"isPublished": true
}
This is clearly being registered in express, as if I log the object I can see this data (plus timestamps and an _id):
{ _id: 5b07d9c0b8124e0599079c04,
postTitle: 'title goes here',
postContent: 'body goes here',
isPublished: true,
createdAt: 2018-05-25T09:39:12.869Z,
updatedAt: 2018-05-25T09:39:12.869Z,
__v: 0 }
However, when I send a get request to my route on this object using its ID, I receive the following in response:
{ "_id": "5b07d9c0b8124e0599079c04" }
Likewise, if I send a request to list all objects, I receive the following response:
{
"posts": [
{
"_id": "5b07d9c0b8124e0599079c04"
},
{
"_id": "5b07d9c0b8124e0599079c03"
},
{
"_id": "5b07d9914f10ce058f137eba"
}
]
}
Weirdly, sometimes the post title sent as part of the response is included in the response, and sometimes it isn't.
My schema is as follows:
var postSchema = new Schema({
postTitle: String,
postContent: String,
isPublished: Boolean
},
{
timestamps: true
});
My post API route for POST requests is as follows:
router.post('/posts', (req, res, next) => {
var postTitle = req.body.postTitle;
var postContent = req.body.postContent;
var isPublished = req.body.isPublished;
var newPost = new Post({
postTitle: postTitle,
postContent: postContent,
isPublished: isPublished
});
newPost.save(function (error) {
if (error) {
console.log(error)
}
res.send({
success: true,
message: 'Post saved successfully!'
})
})
});
(If you're not using Router, you'll have 'app.post' instead of 'router.post') Again, this is a bit longwinded but everything works fine.
My GET route is as follows:
router.get('/posts', (req, res) => {
Post.find({}, 'title content published', function (error, posts) {
if (error) { console.error(error); }
res.send({
posts: posts
})
}).sort({_id:-1})
});
OK - so, by going through my code in detail I've figured out where I was going wrong and fixed the issue, however, in my searching I found very little in the way of results. I'm pretty new to Express, so I'm going to outline the cause of the issue and how I resolved it in order to potentially save someone else a bunch of time if they make the same stupid mistake.
Now, the issue I'm having results from the way I was retrieving the data and serving that in response to get requests. As an example, here's my GET route to list all of the objects.
I was entirely focusing on the post request and assuming it was a problem with the database. It turns out what I'd actually done, is in order to make my schemas and routes less confusing, I'd changed the names of the relevant variables. What I'd forgotten to do, however, is update this line in my GET route to reflect the change:
Post.find({}, 'postTitle postContent isPublished', function (error, posts) {
Which I'd left as:
Post.find({}, 'title content published', function (error, posts) {
The reason the title sometimes displayed is that I tried undoing changes back and forth to spot the issue.
I know this is a super basic query but I got stuck on this for the best part of a day, and the only other relevant discussion on this ended with OP saying that it magically fixed itself.
edit: I have realized that this is hanging at the line "res.json(comment);" of my angular-ui-route. Still not sure why.
I'm following through the tutorial here: https://thinkster.io/tutorials/mean-stack. This may be related to the fact that the tutorial is a little outdated. I've uploaded my code in it's current state to http://github.com/orieporter/flappernews
It's a simple reddit clone web app for posting links, comments, and upvoting them. I am getting a "RangeError: Maximum call stack size exceeded" error each time I add the first comment to a post. Subsequent comments work no problem. When I restart my node server and reload the page the comment that broke the server is there. Can anyone help me find the problem here?
Full error:
events.js:160
throw er; // Unhandled 'error' event
RangeError: Maximum call stack size exceeded
at model.Document.$toObject (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\document.js:1962:24)
at model.Document.toJSON (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\document.js:2300:15)
at clone (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:252:18)
at cloneArray (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:362:14)
at clone (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:247:12)
at cloneObject (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:343:13)
at clone (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:260:16)
at model.Document.$toObject (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\document.js:2009:13)
at model.Document.toJSON (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\document.js:2300:15)
at clone (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:252:18)
at cloneObject (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:343:13)
at clone (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:260:16)
at model.Document.$toObject (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\document.js:2009:13)
at model.Document.toJSON (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\document.js:2300:15)
at clone (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:252:18)
at cloneArray (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:362:14)
at clone (c:\Users\source\repos\flapper-news\node_modules\mongoose\lib\utils.js:247:12)
Relevant HTML:
<form ng-submit="addComment()" style="margin-top:30px;">
<h3>Add a new comment</h3>
<div class="form-group">
<input type="text" class="form-control" placeholder="Comment" ng-model="body"></input>
</div>
<button type="submit" class="btn btn-primary">Post</button>
</form>
Angular Controller Function:
$scope.addComment = function () {
if ($scope.body === '') { return; }
posts.addComment(post._id, {
body: $scope.body,
author: 'user'
},
$scope.post);
$scope.body = '';
};
Angular Factory Function:
o.addComment = function (id, comment, post) {
return $http.post('/posts/' + id + '/comments', comment).then(function (response) {
post.comments.push(response.data);
return response.data;
});
};
Relevant Express Route:
router.post('/posts/:post/comments', function (req, res, next) {
var comment = new Comment(req.body);
comment.post = req.post;
comment.save(function (err, comment) {
if (err) { return next(err); }
req.post.comments.push(comment);
req.post.save(function (err, post) {
if (err) { return next(err); }
res.json(comment);
});
});
});
Comment Schema:
var CommentSchema = new mongoose.Schema({
body: String,
author: String,
upvotes: {type: Number, default: 0},
post: {type: mongoose.Schema.Types.ObjectId, ref: 'Post' }
});
Post Schema:
var PostSchema = new mongoose.Schema({
title: String,
link: String,
upvotes: {type: Number, default: 0},
comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});
I was having the same issue and took me a bit (few fun hours!) of console log debugging, Google searching, and thinkster slack hair-pulling to try to figure out what was going on. Mind you, I'm new to all of this, so wrapping my head around everything was probably the biggest challenge.
Upon further inspection, I narrowed down the cause to the res.json(comment) line as well for the create new comment route logic (routes/index.js).
Logically, I didn't understand why the whole comment object was being pushed to the post comments array when all that is needed is the comment object id. So naturally I eventually figured why not just pass the comment object id (comment._id) and see what happens. And wallah, it worked. No more RangeError: Maximum call stack size exceeded.
So that may address the issue, but my curiously stubborn self wants to know why the heck that would matter? Why does it happen only on the first comment for the post but works fine on the others?
router.post('/posts/:post/comments', auth, function(req, res, next) {
var comment = new Comment(req.body);
comment.post = req.post._id; // <-- originally 'req.post'
comment.author = req.payload.username;
comment.save(function(err, comment){
if(err){ return next(err); }
req.post.comments.push(comment._id); // <-- originally 'comment'
req.post.save(function(err, post) {
if(err){ return next(err); }
res.json(comment);
});
});
});
I figured if mongoose was just going to need the post and comment ids and not the entire objects, then why not just save the ids. Storing the complete objects seemed to cause some sort of infinite loop I believe that causes a call stack error during the response. Perhaps because both objects reference each other? But then again, I'm not sure how this all really works so if any experts out there can shed some light, please do. But that should address the issue and hopefully help others. I should mention that this is an error in the actual Flapper News code they provide. I found that out by downloading their completed source code and running it.
It's because res.json(comment); is trying to stringify the Comment object instance you've created on var comment = new Comment(req.body);
But the "stringifying" process is hanging obviously because of the Comment Object size (which is too big and doesn't have to be stringified).
You should be replacing res.json(comment); by something like
res.json({ status: "success" });
So I have already made a Restful API with node and everything works but I am trying to add EJS to it so I can use HTML&CSS, I implemented GET and POST just fine but I am tripping up on DELETE.
Here is my code in my router to delete
listRouter.delete('/:id',
function(req, res) {
req.list = list;
req.list.remove(function(err){
if (err)
res.status(500).send(err);
else
res.redirect('/')
});
});
and here's my EJS for deletion
<form method="DELETE" action="/:id">
<button type="submit">Delete</button>
</form>
and this is the error I receive when I press the button
{
message: "Cast to ObjectId failed for value ":id" at path "_id"",
name: "CastError",
kind: "ObjectId",
value: ":id",
path: "_id"
}
The thing is though the same exact code works if it's modified for JSON so I don't know if its EJS or my Javascript.
Thanks
i think html5 just support post and get in method form attribute
however, in my case if i don't using form for submit, here example
example in html or front end
<a class="btn btn-raised btn-danger" href="/admin/dashboard/detele/<%= data.userId %>">Delete</a></td>
<!-- The href needs to point at a link where data.userId is shown. Hence you need the = after <% for ejs to show the variable. -->
In app.js for the url delete
app.get('/admin/dashboard/detele/:id', users.deleteUser);
in express users.js
exports.deleteUser = function(req, res) {
users.findOneAndRemove({
userId: req.params.id
}, function(err, user) {
if (err) throw err;
console.log("Success");
});
res.redirect('/admin/dashboard');
}
don't forget creating mongo model for mongoose
var skema = new mongo.Schema({
name: String,
email: String,
password: String,
date: {
type: Date,
default: Date.now
},
admin: Boolean
});
var users = mongo.model('accounts', skema);
i using EJS here, hope it's help you
more helpful link1
more helpful link2
giving up use of method-override can be solution
I used different url to solve this.
<form action="/quake/forum/update/<%= post._id %>?_method=put" method="post">
and
<form action="/quake/forum/delete/<%= post._id %>?_method=delete" method="post" class="d-inline">
and router
main router
app.use('/quake/forum',forumRouter); //this is for just making sure explaination clear
sub router (forumRouter)
router.post('/delete/:id', function (req, res) {
and
router.post('/update/:id', function (req, res) {
I have a NodeJS app and I want to insert some data from a form into a table of my MySQL-database by using the sequelize()-method.
So here is my form
<form id="addVideo" method="post">
<input type="url" name="video_url" required></input>
<input type="hidden" value="" name="artist_id"></input>
<input type="hidden" value="youtube" name="type"></input>
</form>
My post function:
$('form#addVideo').submit(function(e){
e.preventDefault();
var form = $(this);
var jsonvideoFormData = utils.serializeToJSON(form);
var xhrData = _.pick(jsonvideoFormData, 'video_url', 'artist_id', 'type');
api.post('/videos', xhrData, function(response){
alert('Video has been added!');
});
});
Then the backend code looks like this:
exports.addVideo = function(req, res, next){
var videoURL = req.body.video_url;
var artistId = req.body.artist_id;
var type = req.body.type;
db.sequelize.query('INSERT INTO social_urls (artist_id,urls,type) VALUES('artistId','videoURL','type')', function(err) {
if(err){
return res.json(400, {response: {code: 400, message:'An error appeared.'}});
} else{
console.log('succes');
res.json(201, {response: {code: 201, message: 'Video has been added'}});
}
});
}
But for some reason I do not know this is not working. Can anyone help me out?
Many thanks!!
I am not an expert in sequelize, but I see there code prone to SQL Injection.
This is wrong:
db.sequelize.query('INSERT INTO social_urls (artist_id,urls,type) VALUES('artistId','videoURL','type')', function(err)
It should be, at least:
db.sequelize.query("INSERT INTO social_urls (artist_id,urls,type) VALUES('" + artistId + "','" + videoURL + "','" + type + "')'", function(err)
But really, I think you should be doing something like this:
var SocialUrl = sequelize.define('SocialUrl', {
videoURL: Sequelize.STRING,
artistId: Sequelize.STRING,
type: Sequelize.STRING
}, {
tableName: 'social_urls',
timestamps: false
});
SocialUrl
.create({
videoURL: videoURL,
artistId: artistId,
type: type
})
.complete(function(err, socialUrl) {
if (err) {
// log error;
} else {
// Do stuff
}
})
this is the actual query to save the data. Steps 2 & 3.
var videoURL = req.body.video_url;
var artistId = req.body.artist_id;
var type = req.body.type;
models.socialUrls.build({
artist_id: artistId,
urls: videoURL,
type: type
})
.save()
.then(anotherTask => {
console.log('the data saved!');
// you can now access the currently saved task with the variable anotherTask... nice!
})
.catch(error => {
console.log('uh oh something wasn't right!');
console.log(error);
// Ooops, do some error-handling
})
If you check out the sequelize docs here:
http://docs.sequelizejs.com/manual/tutorial/instances.html
There are 3 steps to saving the data.
Creating the model
Creating the instance, a.k.a data object within your callback. This is what gets sent to sequelize method to send to db.
Calling the .save() method.
After that you can handle the errors with .catch()
From what it looks like your problem is in your backend code. Make sure your model is correct and the data from your form is getting sent. Once you are sure of that you only need to do steps 2 and 3.
You don't have to JSON serialize data. You can just post the data.
<form id="addVideo" method="post" action="/videos">
<input type="url" name="video_url" required></input>
<input type="hidden" value="" name="artist_id"></input>
<input type="hidden" value="youtube" name="type"></input>
</form>
Remeber to use body-parser
app.use(require("body-parser")());
Now req.body.video_url should have the expected data.