1

I have a simple API in Express that allows the user to 'post' and 'delete' a post title into a MongoDB database. For some reason, when I add a post title, then subsequently 'delete' it, I get the "Cast to ObjectId failed for value "undefined" at path "_id".

It seems that the "_id" doesn't exist when I call 'delete' after I create the post. However, when I refresh the page, then click 'delete', it gets the "_id" perfectly fine and deletes the entry.

Am I doing something wrong in the routing to not have the "_id" generate and able to be pulled from the post immediately?

module.exports = function(router) {

    var Post = require('../models/post.js');

    // middleware for the api requests
    router.use(function(req, res, next) {
        // do logging
        console.log('something is happening.');
        next(); // make sure we go to our next route and don't stop here
    });

    // test route to make sure everything is working (accessed at GET http://localhost:8080/api)

    router.get('/', function(req, res) {
        res.json({ message: 'hooray! welcome to our api!' });   
    });

    // all routes here

    // routes that end in /posts
    router.route('/posts')

        // create a Post (accessed at POST http://localhost:7777/api/posts)
        .post(function(req, res) {
            var post = new Post();
            post.postTitle = req.body.postTitle; // set the post name (comes from request) 
            console.log(post._id);

            // save post and check for errors
            post.save(function(err) {
                if (err)
                    return res.status(300).send(err);

                res.json({ message: 'post created!' });
            });
        })

        // get all Posts (accessed at GET http://localhost:7777/api/posts)
        .get(function(req, res) {
            Post.find(function(err, posts) {
                if (err)
                    return res.send(err);

                res.json(posts);
            });
        });

    // routes that end in /posts for specific id
    router.route('/posts/:post_id')

        // get the post with that id
        .get(function(req, res) {
            Post.findById(req.params.post_id, function(err, post) {
                if (err)
                    return res.send(err);

                res.json(post);
            });
        })

        // update the post with that id
        .put(function(req, res) {
            Post.findById(req.params.post_id, function(err, post) {
                if (err)
                    return res.send(err);

                post.postTitle = req.body.postTitle;

                // save the post
                post.save(function(err) {
                    if (err)
                        return res.send(err);

                    res.json({ message: 'post updated!' });
                });
            });
        })

        // deletes the post with that id
        .delete(function(req, res) {
            Post.findOne({
                _id:req.params.post_id
            }).remove(function(x){
                console.log("removed: ", x);
            });
        })

        .patch(function(req, res) {
            Post.findOne({
                _id: req.body._id
            }, function(err, doc) {
                for (var key in req.body) {
                    dock[key] = req.body[key];
                }
                doc.save();
                res.status(200).send();
            });
        });
}

/

function addPostItem(post){
        posts.push(post);
        triggerListeners();

        helper.post("/api/posts", post);
    }

function deletePost(post) {
        var index = posts.indexOf(post);
        console.log(post);
        posts.splice(index, 1);
        triggerListeners();

        helper.del('api/posts/' + post._id);
    }

/

var $ = require('jquery');

module.exports = {
    get: function(url) {
        return new Promise(function(success, error) {
            $.ajax({
                url: url,
                dataType: 'json',
                success: success,
                error: error
            });
        });
    },
    post: function(url, data) {
        return new Promise(function(success, error) {
            $.ajax({
                url: url,
                type: 'POST',
                data: data,
                success: success,
                error: error
            });
        });
    },
    patch: function(url, data) {
        return new Promise(function(success, error) {
            $.ajax({
                url: url,
                type: 'PATCH',
                data: data,
                success: success,
                error: error
            });
        });
    },
    del: function(url) {
        return new Promise(function(success, error) {
            $.ajax({
                url: url,
                type: 'DELETE',
                success: success,
                error: error
            });
        });
    }
};
Robert Moskal
  • 21,737
  • 8
  • 62
  • 86
bounty
  • 409
  • 1
  • 4
  • 8

1 Answers1

1

In addPostItem you add the post to your client side list of models before you make the POST call. The newly created post you push onto the posts array will NOT have an _id, since it is generated on the server and not returned. As you pass the server an undefined _id to the server for this new post, any api calls against it will fail with the same error.

When you refresh the page and call your get function, all your posts have an _id so everything works correctly.

A typical pattern to follow would be to return created id (or the entire post) to the client on the post creation and then add that to your items array (something like this):

function addPostItem(post){
    triggerListeners();

    helper.post("/api/posts", post, function(res){
        posts.push(res.data);
    });
}

You'd also need to rewrite your POST request to return the created entity:

post.save(function(err) {
            if (err)
                return res.status(300).send(err, o);

            res.json(o);
        });

A variation would be to return just the ._id. Another would be to create the id on the client side, but then you lose some of the advantages of the native mongo ObjectIds.

Robert Moskal
  • 21,737
  • 8
  • 62
  • 86
  • I don't see the _id anywhere on the ui element. I believe it should be getting the _id when deleting from the database. The _id is auto-generated and added to the MongoDB document, so shouldn't it be able to be retrieved? – bounty Jan 25 '16 at 05:16
  • Where does req.params.post_id on the deletion come from? – Robert Moskal Jan 25 '16 at 05:22
  • It's from the API URL request. I added the delete function in the PostStore. And, the RestHelper file. Hopefully that helps make sense of it. – bounty Jan 25 '16 at 05:33
  • @Robert_Moskal any ideas? I added the addPostItem() function above. – bounty Jan 25 '16 at 17:16