Asked  6 Months ago    Answers:  5   Viewed   43 times

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

 Answers

97

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
Tuesday, June 1, 2021
 
mozlima
answered 6 Months ago
85

What you're seeing is the expected behavior.

The FirestorePagingAdapter in the FirebaseUI library is designed to get data, not to listen for realtime updates.

Saturday, June 19, 2021
 
binoculars
answered 6 Months ago
62

Create an object that will hold your data, eg. ClientData
Create a method for fetching all data from the database

public List<ClientData> selectAll() {
   List<ClientData> list = new ArrayList<ClientData>();
   Cursor cursor = this.myDataBase.query(TABLE_NAME, new String[] { "userID, clientName" },
   null, null, null, null, null);
   if (cursor.moveToFirst()) {
        do {
           list.add(new ClientData(cursor.getString(0), cursor.getString(1)));
         } while (cursor.moveToNext());
   }
   if (cursor != null && !cursor.isClosed()) {
         cursor.close();
   }
   return list;
}

Before executing your insert statements, fetch all data and then check if data exists:

if (!list.contains(clientData)) {
    executeInsert();
}

I am not sure if SQLite supports stored procedures, but if it does, you could write a stored procedure for that as well.

Friday, August 6, 2021
 
leetwinski
answered 4 Months ago
49

this query:

SELECT DISTINCT ROUTINENAME, RESULT_SETS, REMARKS 
FROM SYSIBM.SYSROUTINES 
WHERE ROUTINESCHEMA='<schema>' AND FUNCTION_TYPE NOT IN ('S', 'T')

(where you specify your schema name at the placeholder) gives you all procs in a schema. So the Proc exists part is simply an EXISTS query on that view with the proper proc name.

Tuesday, August 31, 2021
 
whizzzkey
answered 3 Months ago
10

It turned out to be an issue with the Firestore Query. Previously, I had used:

mQuery = mFirestore.collection("courses").whereEqualTo("name", true).limit(LIMIT);

However, it appears that you must use the orderBy() method when making a Firestore Query. Using the following did the trick:

mQuery = mFirestore.collection("courses").orderBy("name").limit(LIMIT);

Now my data is showing up in the RecyclerView as anticipated.

Friday, September 3, 2021
 
neon29
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share