Upvote and Downvote with Backbone, Express and Mongoose Upvote and Downvote with Backbone, Express and Mongoose mongoose mongoose

Upvote and Downvote with Backbone, Express and Mongoose


There're many things that can be improved:

First, you client-side code is a low hanging fruit for an attacker - you do an atomic operation (upvote/downvote) with two requests, and the first request not only sends vote type but also sends total number of votes:

this.set ({votetype : 1 }, {votes : this.get('votes') + 1});this.save();// btw this looks broken, the second argument for `set` is options, so // if you want to set votes, you should move them to the first argument:this.set ({votetype : 1, votes : this.get('votes') + 1});

But, how your application will respond if the attacker will send 100 or even 1000 votes?This operation should be atomic, and you should increment votes on the server when you make POST request to the /upvote endpoint.

Second, you don't really need to store votetype on the post itself - whenever user votes, you change the votetype which is visible for all users but you later hide it with the loop and it just strange to store a votetype of the last vote on the post where you clearly need to have a votetype of the particular user, therefore, you don't need it in the schema and can remote it.You can remove votetype from the posts and you can remove the loop by storing votes history on the post itself, so whenever you want to display a post or a list of posts, you can easily filter the array to contain just the vote of the given user, so you schema will look like this:

var postSchema = new Schema({   name: String,   votesCount: Number,   votes: [{ user_id : mongoose.Schema.Types.ObjectId , type: Number }],   postedBy: { type: String, ref: 'User' },});

And then you can get a post and filter votes with something like:

Post.findOne({_id:<post-id>)}, function(err, post){     post.vote = post.votes.filter(function(vote){         return vote.user_id === req.body.userID;     })[0].type;     res.send(post)  })// or list of postsPost.find(function(err, posts){     posts.forEach(function(post){         post.vote = post.votes.filter(function(vote){             return vote.user_id === req.body.userID;         })[0].type;     });     res.send(posts)  })// you can move vote finding logic in a function: function findVote(post) {    var vote = post.votes.filter(function(vote){        return vote.user_id === req.body.userID;    })[0]    if(vote) return vote.type;}

If you need to display latest voted posts in the user profile you can filter posts voted by the user:

Post.find({'votes.user_id': req.body.userID}, function(err, posts){     posts.forEach(function(post){         // using findVote defined above         post.vote = findVote(post);     });     res.send(posts)  })

Template code on the client side should remain almost the same.