gpt4 book ai didi

node.js - 使用 Backbone、Express 和 Mongoose 支持和反对

转载 作者:IT老高 更新时间:2023-10-28 23:21:13 26 4
gpt4 key购买 nike

我正在尝试实现一个类似于 stackoverflow 或 reddit 的投票系统,其中用户只能在给定的帖子上投票一次。

遵循此处给出的建议后

storing upvotes/downvotes in mongodb

我创建了两个模式来存储赞成票和反对票。对于每个用户,我都会跟踪用户投票的帖子。

发布架构:

var postSchema = new Schema({
name: String,
votes: Number,
votetype: Number,
postedBy: { type: String, ref: 'User' },
});

用户架构:

var userSchema = new Schema({
twittername: String,
twitterID: Number,
votedPosts : [{ _id : mongoose.Schema.Types.ObjectId , votetype: Number }]
});

根据当前用户,每个帖子都会有不同的 View ,如果用户在 upvote 按钮或 downvote 按钮变为橙色(类似于 stackoverflow)之前对帖子投票,那么我有以下(简化)帖子的主干模型:

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);
}

});

},


});

因此,如果用户之前没有对帖子投票,则 votetype 以“0”开头,根据投票情况,它的“1”或“-1”。在 upvote 函数中,当我更新并保存该帖子的投票类型时,我还发送了一个 ajax 请求以将该帖子添加到帖子 Controller 中用户的投票帖子数组中,如下所示:

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();
};

我可能有一些糟糕的设计决定,但到目前为止,这似乎工作正常。请告诉我是否可以对我的代码或我的设计进行任何改进。

现在是棘手的部分。不知何故,在执行 collection.fetch() 之前,我必须查看这两种模式并更改每个帖子的“投票类型”。我想出了一个像这样的丑陋解决方案:

https://gist.github.com/gorkemyurt/6042558

(我把它放在一个 gits 中,所以它可能更具可读性,对不起丑陋的代码..)

一旦我根据用户更新每个帖子的投票类型,我会将其传递给我的主干 View ,并在我的模板中执行一些非常基本的操作,例如:

<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>

此解决方案有效,但我认为每次用户打开页面以呈现帖子的自定义 View 时查找所有帖子和用户投票的所有帖子并不是很有效。任何人都可以想到更好的方法来做到这一点?我愿意接受有关我的代码的任何建议或批评。在此先感谢

最佳答案

有很多地方可以改进:

首先,您的客户端代码对于攻击者来说是唾手可得的成果 - 您使用两个请求执行原子操作(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});

但是,如果攻击者发送 100 甚至 1000 票,您的应用程序将如何响应?这个操作应该是原子的,当你向 /upvote 端点发出 POST 请求时,你应该增加服务器上的投票。

其次,您实际上并不需要在帖子本身上存储 votetype - 每当用户投票时,您都会更改对所有用户可见的 votetype,但您稍后会使用循环将其隐藏,并且存储一个 votetype 很奇怪帖子上的最后一次投票,您显然需要拥有特定用户的投票类型,因此,您不需要它在架构中并且可以远程它。您可以从帖子中删除投票类型,并且可以通过在帖子本身上存储投票历史记录来删除循环,因此无论何时要显示帖子或帖子列表,您都可以轻松过滤数组以仅包含给定的投票用户,因此您的架构将如下所示:

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

然后您可以通过以下方式获得帖子并过滤投票:

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;
}

如果您需要在用户个人资料中显示最新投票的帖子,您可以过滤用户投票的帖子:

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)
}
)

客户端的模板代码应该几乎保持不变。

关于node.js - 使用 Backbone、Express 和 Mongoose 支持和反对,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17756076/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com