Gor*_*ven 10 mongoose mongodb database-schema node.js backbone.js
我正在尝试实现类似于stackoverflow或reddit的投票系统,其中只允许用户在给定帖子上投票一次.
遵循这里给出的建议
我创建了两个模式来存储upvotes和downvotes.对于每个用户,我都会跟踪用户投票的帖子.
发布架构:
var postSchema = new Schema({
name: String,
votes: Number,
votetype: Number,
postedBy: { type: String, ref: 'User' },
});
Run Code Online (Sandbox Code Playgroud)
用户架构:
var userSchema = new Schema({
twittername: String,
twitterID: Number,
votedPosts : [{ _id : mongoose.Schema.Types.ObjectId , votetype: Number }]
});
Run Code Online (Sandbox Code Playgroud)
取决于每个柱都将有一个不同的视图中的当前用户,如果用户已表决的给予好评按钮或downvote按钮之前柱将是橙色(类似于计算器),所以我有以下(简化的)主链帖子模型:
var PostModel = Backbone.Model.extend({
urlRoot : '/tweet',
idAttribute: '_id',
defaults:{
name: '',
votes: 0,
votetype: 0,
postedBy : '',
},
upvote: function(){
this.set ({votetype : 1 }, {votes : this.get('votes') + 1});
this.save();
$.ajax({
type: "POST",
url:"/upvote",
data : {postID : this.id , userID : window.userID , vote: 1},
success : function(result){
console.log(result);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
}
});
},
});
Run Code Online (Sandbox Code Playgroud)
因此,如果用户之前没有投票,则投票类型以"0"开头,并且根据投票,其"1"或"-1".在upvote函数中,当我更新并保存该帖子的votetype时,我还发送一个ajax请求,将该帖子添加到帖子控制器中的用户投票帖子数组中,如下所示:
exports.upvote = function(req,res){
var postID = req.body.postID;
var newvotetype = req.body.vote;
User.findOne({twitterID : req.body.userID}, {votedPosts : { $elemMatch: { "_id": postID }}},
function(err, post) {
if (post.votedPosts.length == 0) {
//append to the array
User.update({twitterID : req.body.userID} , { $push : {votedPosts : {_id : postID , votetype: newvotetype}}} ,function (err, user, raw) {
if (err){console.log(err);}
});
console.log(post);
console.log("no one has voted on this before");
}
else {
//update in the existing array
User.update({twitterID : req.body.userID, 'votedPosts._id': postID }, { $set : {'votedPosts.$.votetype' : newvotetype}} ,function (err, user, raw) {
if (err){console.log(err);}
});
}
}
);
res.send("success");
res.end();
};
Run Code Online (Sandbox Code Playgroud)
我可能有一些糟糕的设计决定,但到目前为止似乎这样做很好.如果我可以对我的代码或我的设计上的任何其他内容进行一些改进,请告诉我.
现在是棘手的部分.不知何故,我必须查看这两个模式并在进行collection.fetch()之前更改每个帖子的"votetype".我想出了一个像这样的丑陋解决方案:
https://gist.github.com/gorkemyurt/6042558
(我把它放在一个gits所以也许它更具可读性,对于丑陋的代码感到抱歉..)
一旦我根据用户更新每个帖子的投票类型,我将其传递给我的骨干视图,在我的模板中,我做了一些非常基本的事情,如:
<div class="post-container">
<div id="arrow-container">
<% if (votetype == 1 ) { %>
<p><img id="arrowup" src="/images/arrow-up-orange.jpg"></p>
<p><img id="arrowdown" src="/images/arrow-down.jpg"></p>
<% } %>
<% if ( votetype == 0 ) { %>
<p><img id="arrowup" src="/images/arrow-up.jpg"></p>
<p><img id="arrowdown" src="/images/arrow-down.jpg"></p>
<% } %>
<% if ( votetype == -1 ) { %>
<p><img id="arrowup" src="/images/arrow-up.jpg"></p>
<p><img id="arrowdown" src="/images/arrow-down-orange.jpg"></p>
<% } %>
</div>
<div id="text-container">
<p><h2><%- name %></h2></p>
<p><%- dateCreated %></p>
<p>Posted by: <%- postedBy %></p>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
该解决方案的工作,但我不认为它真的有效查找所有职位,所有职位用户已表决的每次用户打开页面渲染职位的自定义视图..谁能想到一个更好的这样做的方法?我愿意接受有关我的代码的任何建议或批评..提前感谢
有很多事情可以改进:
首先,您的客户端代码对于攻击者来说是一个悬而未决的成果 - 您使用两个请求执行原子操作(upvote/downvote),并且第一个请求不仅发送投票类型而且还发送总投票数:
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});
Run Code Online (Sandbox Code Playgroud)
但是,如果攻击者发送100票甚至1000票,您的应用程序将如何响应?此操作应该是原子操作,当您向/upvote端点发出POST请求时,应该在服务器上增加投票.
其次,你真的不需要在帖子本身上存储选票类型 - 每当用户投票时,你改变所有用户都可见的投票类型,但你稍后用循环隐藏它,并且存储最后投票的选票类型很奇怪在您明确需要特定用户的投票类型的帖子上,因此,您在模式中不需要它并且可以远程访问它.你可以从帖子中删除votetype,你可以通过在帖子本身上存储投票历史来删除循环,所以每当你想要显示帖子或帖子列表时,你可以轻松过滤数组以包含给定的投票用户,因此您的架构将如下所示:
var postSchema = new Schema({
name: String,
votesCount: Number,
votes: [{ user_id : mongoose.Schema.Types.ObjectId , type: Number }],
postedBy: { type: String, ref: 'User' },
});
Run Code Online (Sandbox Code Playgroud)
然后你可以获得一个帖子并过滤投票,例如:
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 posts
Post.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;
}
Run Code Online (Sandbox Code Playgroud)
如果您需要在用户个人资料中显示最新投票的帖子,您可以过滤用户投票的帖子:
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)
}
)
Run Code Online (Sandbox Code Playgroud)
客户端的模板代码应保持几乎相同.
| 归档时间: |
|
| 查看次数: |
3134 次 |
| 最近记录: |