在将新数据添加到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;
}
}
答案 0 :(得分:2)
从Cloud Firestore加载数据异步进行。到您从alreadyBooked
返回时,尚未加载数据,onSuccess
尚未运行,并且flag
仍具有其默认值。
最简单的方法是使用一些日志语句:
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");
}
如果运行此代码,它将打印:
启动监听器
返回
从Firestore获取数据
这可能不是您期望的顺序。但这完美地解释了为什么在调用false
时总是得到alreadyBooked
的原因:数据只是没有及时从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
的可重用性降低了,因为它现在也包含用于插入新项目的代码。您可以通过定义自己的回调接口来解决此问题:
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实时数据库):