How to skip initial data and trigger only new updates in Firestore Firebase?

I've searched everywhere with no luck. I want to query Firestore to get all users WHERE type is admin. Something like:

SELECT * FROM users WHERE type=admin

but only when the property total is changing. If I'm using:

users.whereEqualTo("type", "admin").addSnapshotListener(new EventListener<QuerySnapshot>() {
    @Override
    public void onEvent(@Nullable QuerySnapshot snapshots, @Nullable FirebaseFirestoreException e) {
        for (DocumentChange dc : snapshots.getDocumentChanges()) {
            switch (dc.getType()) {
                case ADDED:
                    //Not trigger
                    break;
                case MODIFIED:
                    //Trigger
                    break;
                case REMOVED:
                    //
                    break;
            }
        }
    }
});

The case ADDED is triggered first time when I query and when the total is changed case MODIFIED is triggered again (this is what is want). I want only changes and not the all initial data, I don't need it. How to get it?

Please help me, is the last part of my project. How to skip is case ADDED?


Solution 1:

When you are listening for changes in Cloud Firestore for realtime changes, using Firestore Query's addSnapshotListener() method, it:

Starts listening to this query.

Which basically means that first time you attach the listener, you get all documents that correspond to that particular query. Furthermore, everytime a property within a document changes, you are notified according to that change. Obviously, this is happening only if the listener remains active and is not removed.

Unfortunately, Firestore listeners don't work that way, so you cannot skip that "case ADDED". What you can do instead, is to add add under each user object a Date property (this is how you can add it) and query your database on client, according to this new property, for all documents that have changed since a previous time.

According to Nick Cardoso's comment, for future visitors that might ask why this behaviour happens, is because the reason he mentioned in his comment. I also recommend see Doug Stevenson's answer from this post, for a better understanding.

Solution 2:

There is an option to check if the querySnapshot is from a cache, changes return false

if(querySnapshot.getMetadata().isFromCache()) return

Solution 3:

Here is a solution working for me: use

AtomicBoolean isFirstListener = new AtomicBoolean(true);

and then on event method

if (isFirstListener.get()) {
                    isFirstListener.set(false);
                    //TODO Handle the entire list. 
                    return;
                }

Here is a sample code from my project:

 final AtomicBoolean isFirstListener = new AtomicBoolean(true);
 mDb.collection("conversation_log").document(room_id).collection("messages").orderBy("sent_at")
    .addSnapshotListener(new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(@Nullable QuerySnapshot value2, @Nullable FirebaseFirestoreException e) {
        if (isFirstListener.get()) {
            isFirstListener.set(false);
            //TODO Handle the entire list.
            return;
        }
    }
});

reference: answer