11

ユーザーが特定の投稿に対して 1 回しか投票できない、stackoverflow や reddit に似た投票システムを実装しようとしています。

ここで与えられたアドバイスに従った後

mongodbに賛成票/反対票を保存する

賛成票と反対票を格納する 2 つのスキーマを作成しました。ユーザーごとに、ユーザーが投票した投稿を追跡しています。

投稿スキーマ:

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

現在のユーザーに応じて、各投稿のビューが異なります。ユーザーが投稿に投票した場合、賛成ボタンまたは反対投票ボタンがオレンジ色になる (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 リクエストも送信します。

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() を実行する前にすべての投稿の「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>

このソリューションは機能しますが、ユーザーがページを開いて投稿のカスタムビューをレンダリングするたびに、すべての投稿とユーザーが投票したすべての投稿を検索するのは本当に効率的だとは思いません。これを行う方法は?私は自分のコードに関するアドバイスや批判を受け入れます..事前に感謝します

4

1 に答える 1