android - 如何检查某个数据是否已经存在于firestore中

标签 android firebase google-cloud-firestore

在将新数据添加到 firestore 之前,我想检查数据库中是否已经存在同类数据。如果已经存在数据意味着我想防止用户在数据库中输入重复数据. 在我的情况下,如果已经存在同一时间的预订,它就像一个约会预订,我想防止用户同时预订。我尝试使用查询功能,但它并没有阻止重复数据输入。请有人帮助我

private boolean alreadyBooked(final String boname, final String bodept, final String botime) {
        final int[] flag = {0};
        CollectionReference cref=db.collection("bookingdetails");
        Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
        q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
            @Override
            public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
                for (DocumentSnapshot ds : queryDocumentSnapshots) {
                    String rname, rdept, rtime;
                    rname = ds.getString("name");
                    rdept = ds.getString("dept");
                    rtime = ds.getString("time");
                    if (rdept.equals(botime)) {
                        if (rtime.equals(botime)) {
                            flag[0] = 1;
                            return;
                        }
                    }
                }
            }
        });
        if(flag[0]==1){
            return true;
        }
        else {
            return false;
        }
    }

最佳答案

从 Cloud Firestore 加载数据是异步发生的。当您从 alreadyBooked 返回时,数据尚未加载,onSuccess 尚未运行,并且 flag 仍具有其默认值值(value)。

查看此内容的最简单方法是使用一些日志语句:

private boolean alreadyBooked(final String boname, final String bodept, final String botime) {
    CollectionReference cref=db.collection("bookingdetails");
    Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
    System.out.println("Starting listener");
    q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
            System.out.println("Got data from Firestore");
        }
    });
    System.out.println("Returning");
}

如果你运行这段代码,它会打印:

Starting listener

Returning

Got data from Firestore

这可能不是您期望的顺序。但这完美地解释了为什么在调用 alreadyBooked 时总是得到 false:数据只是没有及时从 Firestore 返回。

解决这个问题的方法是改变你思考问题的方式。您当前的代码具有逻辑:“首先检查是否已预订,然后添加新项目”。我们需要将其重新定义为:“开始检查它是​​否已被预订。一旦我们知道还没有,就添加一个新项目。”在代码中,这意味着所有需要来自 Firestore 的数据的代码都必须在 onSuccess 中,或者必须从那里调用。

最简单的版本是将代码移到onSuccess:

private void alreadyBooked(final String boname, final String bodept, final String botime) {
    CollectionReference cref=db.collection("bookingdetails");
    Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
    q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
            boolean isExisting = false
            for (DocumentSnapshot ds : queryDocumentSnapshots) {
                String rname, rdept, rtime;
                rname = ds.getString("name");
                rdept = ds.getString("dept");
                rtime = ds.getString("time");
                if (rdept.equals(botime)) {
                    if (rtime.equals(botime)) {
                        isExisting = true;
                    }
                }
            }
            if (!isExisting) {
                // TODO: add item to Firestore
            }
        }
    });
}

虽然这很简单,但它使 alreadyBooked 的可重用性降低,因为现在它也包含插入新项目的代码。您可以通过定义自己的回调接口(interface)来解决这个问题:

public interface AlreadyBookedCallback {
  void onCallback(boolean isAlreadyBooked);
}

private void alreadyBooked(final String boname, final String bodept, final String botime, AlreadyBookedCallback callback) {
    CollectionReference cref=db.collection("bookingdetails");
    Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
    q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
        @Override
        public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
            for (DocumentSnapshot ds : queryDocumentSnapshots) {
                String rname, rdept, rtime;
                rname = ds.getString("name");
                rdept = ds.getString("dept");
                rtime = ds.getString("time");
                if (rdept.equals(botime)) {
                    if (rtime.equals(botime)) {
                        isExisting = true;
                    }
                }
            }
            callback.onCallback(isExisting)
        }
    });
}

然后你称它为:

alreadyBooked(boname, bodept, botime, new AlreadyBookedCallback() {
  @Override
  public void onCallback(boolean isAlreadyBooked) {
    // TODO: insert item
  }
});

另请参阅(其中许多是针对 Firebase 实时数据库的,其中适用相同的逻辑):

关于android - 如何检查某个数据是否已经存在于firestore中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51000169/

相关文章:

java - 如何替换 Activity 中的 textChangedListener

android - 自定义 FragmentTabHost 在底部设置 TabWidget

android - 调试android时Eclipse挂起

php - FCM_SENDER_ID 或 FCM_SERVER_KEY 在 laravel/brozot 中无效

javascript - 引用错误 : context is not defined

java - Firebase 存储 - 防止覆盖文件

python - 我在 Firestore 中执行了多少次读取?

java - 使用 Firestore 获取我关注的人的帖子

android - 失败1 :Syntax error

firebase - 为什么我的服务帐号无法远程访问 Google Cloud Firestore?