我有Article
,Comment
和Feedback
猫鼬模特。它类似于facebook场景,其中use可以写article
,在comment
下写article
,feedback
like
,{{1} },dislike
)share
或comment
。
基本理念是,用户可以使用article
或like unlike dislike undislike share unshare
发送articleId
等操作。 (commentId
将取消unlike
,like
将取消undislike
)
用户最多只能dislike
feedback
target (article/comment)
。一个用于twice
,一个用于like/dislike
然后我这样做:
如果存在share
(Target
或Article
)
一个。如果反馈不存在,请创建一个。然后使用新的Comment
列表
Target
湾ELSE(例如,用户在feedbacks
like
之间切换),更新状态(例如unlike
- > deleted
,normal
- > like
),然后使用新的dislike
列表
Target
ELSE(目标不存在)报告错误
以下是我对反馈的实施。
feedbacks
正如您所看到的,代码变得非常庞大和混乱。有什么好方法可以清理它吗?还是有更好的编码风格?
编辑:承诺的代码。我可以只有1个错误处理程序。我也是exports.sendFeedback = function(req, res, next) {
var articleId = req.body.articleId
var commentId = req.body.commentId
var action = req.body.action
var meta = req.body.meta
var Target
var targetId
if (articleId) {
Target = Article
targetId = articleId
}
else if (commentId) {
Target = Comment
targetId = commentId
}
//1. find the target
//Note: will refetch when need to send json, since feedback has been changed
Target.findById(targetId).exec(function(err, target) {
if (err)
return next(err)
if (!target)
return next(helper.getGeneralError('target does not exist'))
//2. find the feedback
var criteria = {}
criteria['statusMeta.createdBy'] = req.user
if (action === 'like' || action === 'dislike' || action === 'unlike' || action === 'undislike')
criteria['type'] = {$in: ['like', 'dislike']}
else if (action === 'share' || action === 'unshare')
criteria['type'] = 'share'
if (articleId)
criteria['target.article'] = articleId
else if (commentId)
criteria['target.comment'] = commentId
Feedback.find(criteria).exec(function(err, feedbacks) {
if (err)
next(err)
if (feedbacks.length === 0) {
//3. Feedback does not exist, create it
var newFeedback = new Feedback()
if (action === 'like' || action === 'dislike' || action === 'share') {
newFeedback.type = action
newFeedback.status = 'normal'
newFeedback.statusMeta.createdBy = req.user
if (articleId)
newFeedback.target.article = targetId
else if (commentId)
newFeedback.target.comment = targetId
if (meta)
newFeedback.meta= meta
}
newFeedback.save(function(err) {
if (err)
return next(err)
//4. save to target feedbacks list
target.feedbacks.push(newFeedback)
target.save(function(err) {
if (err)
return next(err)
//5. save to user feedbacks list
req.user.feedbacks.push(newFeedback)
req.user.save(function(err) {
if (err)
return next(err)
//6. done
//Note: send the target!
//Note: refetch target and populate, since its feedbacks have been changed
var query = Target.findById(targetId)
populateUsersForQuery(query)
populateFeedbacksForQuery(query)
query.exec(function(err, target) {
if (err)
return next(err)
return res.json(target)
})
})
})
})
}
else {
//3x. Found the feedback, update it
var feedback = feedbacks[0] //must be length 1
if (action === 'like' || action === 'dislike' || action === 'share') {
feedback.type = action
feedback.status = 'normal'
feedback.statusMeta.updatedBy = req.user
feedback.statusMeta.updatedDate = new Date
}
else if (action === 'unlike' || action === 'undislike' || action === 'unshare') {
feedback.status = 'deleted'
feedback.statusMeta.deletedBy = req.user
feedback.statusMeta.deletedDate = new Date
}
if (meta)
feedback.meta= meta
feedback.save(function(err) {
if (err)
return next(err)
//4x. done
//Note: send the target!
//Note: refetch target and populate, since its feedbacks have been changed
var query = Target.findById(targetId)
populateUsersForQuery(query)
populateFeedbacksForQuery(query)
query.exec(function(err, target) {
if (err)
return next(err)
return res.json(target)
})
})
}
})
})
}
或return next(err)
吗?
编辑2:2个案例的最后步骤是相同的(获取,填充和发送)。我可以结合2吗?
编辑3:代码无效。在第一个throw err
中,我们有then
作为参数。在随后的target
中,then
变为未定义
target
答案 0 :(得分:2)
正如我的评论中所提到的,也许你可以简化这个并减少对数据库的调用次数。
现在你:
如果没有:
如果确实存在*:
您还可以将完整的反馈保存到req.user。
现在,我建议稍作修改,以便在您不需要时不进行最初的两次通话。
您可以按原样保留req.user.feedbacks然后检查那里,或者可以简化该位,使其像旗帜一样。
即(计算的道具名称的es6语法):
req.user.feedbacks = {
[articleId:action]: true,
[anotherArticle:action]: false
// ... etc
};
所以当你点击请求时:
Please like article 1124:
您可以在加载任何内容之前进行检查:
exports.sendFeedback = function(req, res, next) {
var articleId = req.body.articleId;
var commentId = req.body.commentId;
var action = req.body.action;
var meta = req.body.meta;
var targetId = articleId || commentId; // skipping error check
if (req.user.feedbacks[targetId + ':' + action]) {
// now you already know the user already liked/disliked stuff, and you can only flip it here
req.user.feedbacks[targetId + ':' + action] = /like/unlike/whatever you need/
Feedback.update({id: ...}, {$set: {action: /whatever/}});
}
// if it doesn't exist, create anew.
// ... [cut] ...
所以我的观点是,改变req.user.feedbacks上的类似结构,然后你不必检查所有地方。
希望有所帮助。
[*] - 注意:您可以使用Feedback.findOne()来避免feedbacks.length检查。
答案 1 :(得分:1)
使用async npm包。使用瀑布控制流程,您可以解决您的问题。
async.waterfall([
function(callback) {
Target.findById(targetId).exec(function(err, target) {
if(err)
callback(err);
else
callback(null,target);
})
},
function(target, callback) {
Feedback.find(criteria).exec(function(err, feedbacks) {{
if(err)
callback(err);
else
callback(null,target);
})
},
function(feedbacks, callback) {
newFeedback.save(function(err,result) {
if(err)
callback(err);
else
callback(null,result);
})
}
], function (err, result) {
// result now equals 'done'
});