0

My studentApi.js is as follows, router.param() is used to save code for repeating again and againt.

router.param('post', function (req, res, next, id) {
    var query = Post.findById(id);
    query.exec(function (err, post) {
        if (err) { return next(err); }
        if (!post) { return next(new Error('Can\'t find post')); }
        req.post = post;
        return next();
    })
});
router.put('/posts/:post/upvote', function (req, res, next) {
    res.post.upvote(function (err, post) {
        if (err) { return next(err);}
    });
});

In angular I am calling like

 o.upvote = function (post) {
        return $http.put('/studentapi/posts/' + post._id + '/upvote')
          .success(function (data) {
              alert("post voted");
              post.upvotes += 1;
          });
    };

Error: enter image description here

My model is as follows, calling upvote method internally from model.

var mongoose = require('mongoose');
var PostSchema = new mongoose.Schema({
    title: String,
    link: String,
    upvotes: { type: Number, default: 0 },
    downvotes: { type: Number, default: 0 },
    comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});

mongoose.model('Post', PostSchema);

PostSchema.methods.upvote = function (cb) {
    this.upvotes += 1;
    this.save(cb);
}

enter image description here

Nomi Ali
  • 2,165
  • 3
  • 27
  • 48
  • is your api up and running? And in your studentApi.js there is only 'post/:post' where is the code initializing it with "/studentapi" ? Could be possible that you're missing some initialization. Try out PUT on "/posts/" without "studentapi" . Or you have "/studentApi" and not "studentapi" – Fer To Oct 11 '15 at 10:14
  • Yup, api is up and running, already working with simple get request. I get the record from db and bind successfully. In this case I'm updating record I pass the parameter as above but 404. – Nomi Ali Oct 11 '15 at 10:17
  • studentApi.js seem to be executed server-side with node, so alert() should not exist except if you import a function with the same name. Then, what is res.post, is it a mongodb linked model? And finally what have you in the node console? – KyleK Oct 11 '15 at 10:18
  • 1
    Well, you're providing your "get" route where is the .put route ? I mean you can't do an HTTP PUT if you just have a "GET" defined for that URL. – Fer To Oct 11 '15 at 10:18
  • router.get('/posts', function (req, res, next) working fine! – Nomi Ali Oct 11 '15 at 10:19
  • It is "get". Now you need "post"/"put" methods. – KyleK Oct 11 '15 at 10:19
  • you need "router.put("/posts"..) and just delete this "alert" line as you're working with a server. – Fer To Oct 11 '15 at 10:22
  • And the best thing would be to just debug your post with node-inspector. As you're lines look fine. – Fer To Oct 11 '15 at 10:24
  • @FerTo updated my question. – Nomi Ali Oct 11 '15 at 10:26
  • Error 500 means you have something to read in your nodejs console as I suggest in my first comment. – KyleK Oct 11 '15 at 10:36
  • Is res.post.upvote undefined if you log it? It looks like you are incrementing this value in your success callback. Maybe that value/property doesn't exist yet? – Chris L Oct 11 '15 at 10:39
  • @ChrisL updated my question please have a look! – Nomi Ali Oct 11 '15 at 10:43
  • yeah, I don't think you've gotten your post by id yet? So, res.post is returning undefined. – Chris L Oct 11 '15 at 10:48
  • Jepp, you should make a call to the db to get your post object with the id I think your plain res.post. is an empty object – Fer To Oct 11 '15 at 10:50
  • OK, so res is a response object and do not have "post" unless you attached it in a middleware. So first, you must require your mongo model then upvote on it and call res.json or res.end in the callback. – KyleK Oct 11 '15 at 10:58
  • @kylek I return the required post into res as above, I updated the question. – Nomi Ali Oct 11 '15 at 11:02
  • 1
    Store something in req.post will do nothing because the req will be destroy after the page is loaded, and res.post does not exist, it does not work that way. You must pass the id and re-find the post with the id. Use req.params.post – KyleK Oct 11 '15 at 11:03

2 Answers2

2

How do I update/upsert a document in Mongoose?

Here is a good start. I personally use the following approach recommended at scotch.io

app.put('url', function(req, res) {

    // use our bear model to find the bear we want
    Bear.findById(req.params.bear_id, function(err, bear) {

        if (err)
            res.send(err);

        bear.name = req.body.name;  // update the bears info

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

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

    });
});

https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4

Community
  • 1
  • 1
Chris L
  • 1,051
  • 1
  • 7
  • 20
  • Yup, I can do this by above code, but I actually want to reuse the code for at least getById stuff. – Nomi Ali Oct 11 '15 at 11:06
1

Thanks for all the help it was really appreciated, Actually there was a mistake in Mongoose Model in my case posts.js as I need to attach the model after defining method in Post model. The correct one was

var mongoose = require('mongoose');
var PostSchema = new mongoose.Schema({
    title: String,
    link: String,
    upvotes: { type: Number, default: 0 },
    downvotes: { type: Number, default: 0 },
    comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }]
});

PostSchema.methods.upvote = function (cb) {
    this.upvotes += 1;
    this.save(cb);
}

mongoose.model('Post', PostSchema);

As now I put PostSchema.methods.upvote stuff above the mongoose.model('Post',PostSchema);

Nomi Ali
  • 2,165
  • 3
  • 27
  • 48
  • glad to see you got it worked out. Are you now getting the expected behavior since to added the properties to the post class before declaring the model? – Chris L Oct 11 '15 at 12:22