如何在MongoDB / Mongoose中实现上/下投票系统?

时间:2018-07-05 17:40:52

标签: node.js mongodb mongoose

我是MongoDB的新手,我正在尝试实现upvote / downvote系统,以便用户可以对我的应用程序中的评论进行投票。

我如何设置系统,是用户通过按应用程序中的upvote或downvote按钮通过AJAX发送POST请求,该按钮包含一个布尔值“ upvote”(如果为true,则为upvote;如果为true,则为downvote)。 false(此代码有效,所以我没有包含它)。请求到达服务器后,服务器将检查用户投票的评论是否已经包含投票。如果不是,则服务器向该评论的“投票”数组添加一个投票,并增加或减少该评论的voteBalance属性。如果该评论的“投票”数组中已经存在投票,则应该:

1)如果现有投票的upvote属性与新投票不同,请对其进行修改,然后相应地修改voteBalance,或者

2)如果现有投票的upvote属性与新属性相同,则将其删除,然后相应地修改voteBalance。

我插入新投票的代码可以正常工作,但是我遇到的问题是,我无法弄清楚在已经存在投票的情况下如何使它起作用。在下面的服务器端代码中,靠近底部的else语句是我试图从上方处理情况1)的内容,但是它不起作用。那么如何使这两种情况都起作用?

这是我的评论架构:

var ReviewSchema = new mongoose.Schema({
  authorID: {
    type: String,
    required: true,
  },
  movieID: {
    type: Number,
    required: true,
  },
  date: {
    type: Number,
    required: true
  },
  username: {
    type: String,
    required: true
  },
  score: {
    type: Number,
    required: true
  },
  text: {
    type: String
  },
  voteBalance: {
    type: Number,
    required: true,
    default: 0
  },
  votes: [{
    voterID: {
      type: String,
      required: true,
    },
    upvote: {
      type: Boolean,
      required: true
    }
  }],
  comments: [{
    commenterID: {
      type: String,
      required: true,
    },
    text: {
      type: String,
      required: true
    },
    date: {
      type: Number,
      required: true
    }
  }]
},{collection: 'reviews'});

这是我用来在服务器上创建和更新投票的代码:

Review.findOne({_id: new ObjectID(reviewID), votes: { $elemMatch: { voterID: req.session._id }}}, function(err, review) {
      if (err) {
        console.log(err);
        res.status(500).send();
      }
      //If vote was not found (or if review was not found), create vote
      if (!review) {
        if (upvote) {
          var update = {$addToSet: {votes: {voterID: req.session._id, upvote}}, $inc : {voteBalance : 1}};
        }
        else {
          var update = {$addToSet: {votes: {voterID: req.session._id, upvote}}, $inc : {voteBalance : -1}};
        }

        Review.findOneAndUpdate({_id: new ObjectID(reviewID)}, update, function(err, review) {
          if (err) {
            console.log(err);
            return res.status(500).send();
          }
          res.status(200).send();
        });
      }
      //If vote was found, update
      else {
        if (upvote) {
          var update = {$set: { 'votes.$.upvote': upvote }, $inc : {voteBalance : 1}};
        }
        else {
          var update = {$set: { 'votes.$.upvote': upvote }, $inc : {voteBalance : -1}};
        }

        Review.findOneAndUpdate({_id: new ObjectID(reviewID), 'votes.$.voterID': req.session._id}, update, function(err) {
          if (err) {
            console.log(err);
            return res.status(500).send();
          }
          res.status(200).send();
        });
      }
    });

此外,我认识到这段代码可能效率不高,我也很感谢这方面的任何技巧。

1 个答案:

答案 0 :(得分:1)

与其先做findOne(),然后再做findOneAndUpdate(),不如将findOneAndUpdate()upsert option一起使用,会更好。这样,您就不需要在回调中使用额外的if语句。

我还建议不要将votes作为数组存储在ReviewSchema中。该数组可以无限增长,因为任何数量的用户都可以对Review进行投票,这意味着审阅文档可能会变得庞大而笨拙。我建议改为使用映射集合。