【问题标题】:Android Firestore set limit to 1 vote per userAndroid Firestore 将限制设置为每位用户 1 票
【发布时间】:2019-07-26 18:37:44
【问题描述】:

我正在从头开始创建我的第一个应用程序,它是 android 上的一个论坛应用程序,我已经了解了它的赞成/反对部分。

我已将其设置为我的用户可以投票反对的位置(类似于 StackOverflow),但我不知道如何将其限制为每个用户一票。

我使用 Firebase-Firestore 作为数据库。

我设置了 upvote 和 downvote 切换按钮,以在按钮点击侦听器上更新 firestore 中的分数,每个按钮都有各自的选择器 item.xml

有没有人能阐明一种方法,将用户限制为每个用户每个答案只能投一票,类似于堆栈溢出?

感谢任何和所有的帮助。

编辑

尝试提供的答案之前的当前代码。

应答适配器

public class AnswerAdapter extends FirestoreRecyclerAdapter<Answer, AnswerAdapter.AnswerHolder> {

    private QuestionAdapter.OnItemClickListener listener;
    private Context mContext;
    private static final String TAG = "AnswerAdapter";

    /**
     * Create a new RecyclerView adapter that listens to a Firestore Query.  See {@link
     * FirestoreRecyclerOptions} for configuration options.
     *
     * @param options
     */

    public AnswerAdapter(@NonNull FirestoreRecyclerOptions<Answer> options) {

        super(options);
    }

    @NonNull
    @Override
    public AnswerHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.answer_item, viewGroup, false);
        return new AnswerHolder(v);
    }

    @Override
    protected void onBindViewHolder(@NonNull final AnswerAdapter.AnswerHolder answerHolder, final int position, @NonNull final Answer model) {

        answerHolder.answerItemTextView.setText(model.getAnswer());
        answerHolder.answerAuthorTextView.setText(model.getAuthor());
        answerHolder.answerTimeStampTextView.setText(model.getTimestamp());
        answerHolder.answerScoreTextView.setText(getSnapshots().getSnapshot(position).get("answerScore").toString());

        answerHolder.mAnswerUpVoteButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO: 2019-07-26 check order of operations. seems to go through upvote and then also through downvote unchecking state
                if (answerHolder.mAnswerUpVoteButton.isChecked()){

                    answerUpVote(answerHolder, position, model);
                } else {
//                    answerDownVote(answerHolder, position, model);
                }
            }
        });

public class AnswerHolder extends RecyclerView.ViewHolder{

        TextView answerItemTextView;
        TextView answerScoreTextView;
        ToggleButton answerCheckMark;
        TextView answerAuthorTextView;
        TextView answerTimeStampTextView;
        ToggleButton mAnswerUpVoteButton;
        ToggleButton mAnswerDownVoteButton;


        public AnswerHolder(@NonNull final View itemView) {
            super(itemView);
            answerItemTextView = itemView.findViewById(R.id.answerItemTextViewId);
            answerScoreTextView = itemView.findViewById(R.id.questionScoreId);
            answerCheckMark = itemView.findViewById(R.id.answerCheckMarkId);
            answerAuthorTextView = itemView.findViewById(R.id.answerAuthorTextViewId);
            answerTimeStampTextView = itemView.findViewById(R.id.answerTimeStampTextViewId);
            mAnswerUpVoteButton = itemView.findViewById(R.id.answerUpVoteId);
            mAnswerDownVoteButton = itemView.findViewById(R.id.answerDownVoteId);

            mContext = itemView.getContext();

        }

    }

private void answerUpVote(@NonNull final AnswerAdapter.AnswerHolder answerHolder, final int position, @NonNull final Answer model) {
        final String answerScoreFBValue = getSnapshots().getSnapshot(position).get("answerScore").toString();
        final String answerFirebaseIdString = getSnapshots().getSnapshot(position).get("answerFirebaseId").toString();
//        Toast.makeText(mContext, "upvote button clicked " + answerScoreFBValue, Toast.LENGTH_SHORT).show();
        final CollectionReference answerCollectionRef = FirebaseFirestore.getInstance().collection("Answers");
        final DocumentReference answerDocRef = answerCollectionRef.document(answerFirebaseIdString);


        answerDocRef.update("answerScore", FieldValue.increment(1)).addOnSuccessListener(new OnSuccessListener<Void>() {
            //                answerRef.document().update("answerscore", answerScoreTestInt).addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                Log.d(TAG, "onSuccess: answerScore incremented");
//                answerHolder.answerScoreTextView.setText("testing");

            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.e(TAG, "onFailure: answerScore was not incremented", e);
            }
        });
    }

Answer.java

package com.example.stairmaster.models;

public class Answer {

    private String answer;
    private String comment; 
    private String timestamp;
    private int answerScore;
    private String author;
    private String answerFirebaseId;
    private String parentQuestionId;


    public Answer(String answer, String timeStamp, String author, String parentQuestionId, int answerScore) {

        this.answer = answer;
        this.timestamp = timeStamp;
        this.answerScore = answerScore;
        this.author = author;
        this.parentQuestionId = parentQuestionId;
    }

    public Answer () {
        // public no-arg constructor needed
    }

    public String getAnswerFirebaseId() {
        return answerFirebaseId;
    }

    public void setAnswerFirebaseId(String answerFirebaseId) {
        this.answerFirebaseId = answerFirebaseId;
    }

    public String getAnswer() {
        return answer;
    }

    public void setAnswer(String answer) {
        this.answer = answer;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    public int getAnswerScore() {
        return answerScore;
    }

    public void setAnswerScore(int answerScore) {
        answerScore = answerScore;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getParentQuestionId() {
        return parentQuestionId;
    }

    public void setParentQuestionId(String parentQuestionId) {
        this.parentQuestionId = parentQuestionId;
    }
}

【问题讨论】:

  • 分享一些代码以便我们更好地提供帮助
  • @treewallie,稍后再做。目前在工作场所。
  • 问题解决了吗?
  • @Treewallie,为你添加代码
  • @AlexMamo,还没有。不幸的是,我要到明天或本周晚些时候才能解决它。

标签: java android google-cloud-firestore android-togglebutton


【解决方案1】:

您可以考虑将您的 firebase 数据库中的数据库表修改为如下所示。

user_votes:
  - userid: 1234232 // A sample user id for your user
    - forumid: 8769765 // The id of the forum or blog
      - upvote: 1 // Number of upvotes in that specific forum/blog
      - downvote: 0 // Number indicates the downvote to that forum/blog
    - forumid: 1233432 
      - upvote: 1 
      - downvote: 0 
    - forumid: 8712169767 
      - upvote: 0 
      - downvote: 1 

另一个记录特定论坛/博客的赞成/反对票的表格可能如下所示。

all_votes:
  - forumid: 8769765 // The id of the forum or blog
    - upvote: 9876 // Number of upvotes in that specific forum/blog
    - downvote: 123 // Number indicates the downvote to that forum/blog
  - forumid: 1233432 
    - upvote: 87 
    - downvote: 12 
  - forumid: 8712169767 
    - upvote: 112 
    - downvote: 10

现在,基于这两个表,您可以轻松决定是否要在您的all_votes 表中发出setValue 命令以获得论坛ID。如果发现用户已经发出了赞成票,则使应用程序逻辑不会在all_votes 表中为该特定用户发出另一个赞成票。

希望有帮助!

【讨论】:

  • 感谢您的建议,我会考虑试一试您的方法。我不熟悉“setValue”命令。这让我有一些功课要做。
【解决方案2】:

我正在做类似的事情,我做这件事的方式是使用本地房间数据库。所以首先,它检查本地数据库以查看用户是否可以投票。如果可以,它会向 firestore 发送请求以更新相关字段。我也在使用 RxKotlin 并将返回的 Task(从请求到 firestore)包装到一个 observable 中。如果 observable 完成且没有任何错误,则它会更新本地数据库。如果它失败了,那么它什么也做不了。我相信还有其他方法,但这就是我选择这样做的方式。

【讨论】:

  • 感谢您的建议,直到现在我才知道本地房间数据库。我会看看我是否可以调查一下并试一试。知道它是否与 Firestore 兼容吗?
  • 如果你正确实现它,它会很好地发挥作用。我将所有内容包装到一个可观察对象中(从本地和远程数据库返回的任何内容)。 Reaz 的方法似乎也很出色,但那是对 firestore 的额外读取请求。但是我的方法会更复杂,因为你必须设置本地数据库。
  • 我有另一个想法,但它可能非常原始。我可以将用户投票列表添加到答案模型中。例如,如果用户投票,他们的唯一用户 ID 将被添加到列表中。这样做可以让我跟踪谁投了赞成票或反对票。我可以做到这一点,所以 upvote 或 downvote 是一个按钮单击侦听器,并检查答案的投票者名单。如果有匹配,则不会让该用户投票两次。此列表可以保存在 Firestore 中。这听起来与您的方法相似,尽管它只会使用 Firestore。你怎么看?
  • 是的,它会起作用,但是如果您使用本地数据库,则不必发出额外的写入/读取请求(节省您在 firestore 上的使用/金钱)。此外,额外的网络调用只是更多的故障点。但最终,这取决于您,并且该方法会起作用。
  • 感谢您的提示。过去几天我一直在研究它。人们使用带有本地房间数据库的firestore的实例并不多。您是否偶然发现了任何可以指出我使用这两种方法的人的好例子?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-04
相关资源
最近更新 更多