Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check a certain data already exists in firestore or not

Before adding a new data into the firestore, i want to check already a data of the same kind exists in the database or not.if already a data was present means i want to prevent the user from entering duplicate data in the database. In my case it is like a appointment booking if already a booking for the same time exists,i want to prevent to users to book on the same time.i tried using query function but it is not preventing duplicate data entering.someone plz help me

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;
        }
    }
like image 562
Ragavendra vignesh Avatar asked Jun 23 '18 10:06

Ragavendra vignesh


1 Answers

Loading data from Cloud Firestore happens asynchronously. By the time you return from alreadyBooked, the data hasn't loaded yet, onSuccess hasn't run yet, and flag still has its default value.

The easiest way to see this is with a few log statements:

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

If you run this code it will print:

Starting listener

Returning

Got data from Firestore

That's probably not the order you expected. But it perfectly explains why you always get false when calling alreadyBooked: the data simply didn't come back from Firestore in time.

The solution for this is to change the way you think about the problem. Your current code has logic: "First check if it is already booked, then add a new item". We need to reframe this as: "Start checking if it is already booked. Once we know that is isn't, add a new item." In code this means that all code that needs data from Firestore must be inside the onSuccess or must be called from there.

The simplest version is to move the code into 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
            }
        }
    });
}

While this is simple, it makes alreadyBooked less reusable since now it contains the code to insert the new item too. You can solve this by defining your own callback 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)
        }
    });
}

And then you call it as:

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

Also see (many of these are for the Firebase Realtime Database, where the same logic applies):

  • getContactsFromFirebase() method return an empty list
  • Doug's blog post on asynchronous callbacks
  • Setting Singleton property value in Firebase Listener
  • Android + Firebase: synchronous for into an asynchronous function
  • Is it possible to synchronously load data from Firebase?
  • Querying data from firebase
like image 106
Frank van Puffelen Avatar answered Oct 19 '22 17:10

Frank van Puffelen