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

前端 未结 1 2007
盖世英雄少女心
盖世英雄少女心 2020-11-22 13:24

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 prev

相关标签:
1条回答
  • 2020-11-22 14:17

    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
    0 讨论(0)
提交回复
热议问题