Erik Hellberg Erik Hellberg - 7 days ago 5
Android Question

How to create this Firebase Query to only return items after a specific Push key time

Following up on this grate answer I use the

ValueEventListener
to listen for only new items with this query:

Query query = ref.child(USER)
.child(mFireBaseAuth.getCurrentUser().getUid())
.child(TOYS)
.orderByKey().startAt(-KXN04BDYdEG0aii9mMY);

query.addValueEventListener(mvalueEventListener);


The
-KXN04BDYdEG0aii9mMY
in the code sample above is the latest item i already have and I want to get only push keys after that time stamp. With this code I also get the
-KXN04BDYdEG0aii9mMY
again and that is not needed because I already have it right.

How should I solve this? Maybe add a millisecond to this Firebase push key
-KXN04BDYdEG0aii9mMY
?

Under the
TOYS
key is a list of Firebase Puch keys

Answer

I got it working just like I was asking for in the question. Here is the code since it´s the answer for me, and for anyone's delight.

This was a tricky one I have to both filter away the key that I specify for startAt() and at the same time in the ´onDataChange()´ handle a second call because of TimeStamp correcting from Firebase, when doing ´...ServerValue.TIMESTAMP);´

       // When startAt() get defined this will make sure that we dont save the 
       // startAt key item again.
       // Best would be if the startAfter("pushKey") existed but it does not.
       String skipStartAtKey = "";        


         /**
         * Typically when user sign in or app start
         */
        public void userSignedIn() {
            Log.i(TAG, "userSignedIn");
            // start listening
            activateFirebaseListeners();
        }

         /**
         * When user sign in this listeners are started
         */
        private void activateFirebaseListeners() {

           // [START Listen for history Address changes ]

            /**
             * The ChildEventListener.
             * This is only used when app first install or user wipe data
             */
            ChildEventListener userHistoryAddressChildEventListener = new ChildEventListener() {

                @Override
                public void onChildAdded(DataSnapshot snapshot, String prevKey) {
                    userHistoryAddressChildEvent(snapshot, prevKey);
                }

                @Override
                public void onChildChanged(DataSnapshot snapshot, String prevKey) {
                    userHistoryAddressChildEvent(snapshot, prevKey);
                }

                @Override
                public void onCancelled(DatabaseError error) {
                 // TODO dont forget to remove reset listeners
                }

                @Override
                public void onChildRemoved(DataSnapshot snapshot) {
                }

                @Override
                public void onChildMoved(DataSnapshot snapshot, String prevKey) {
                }
            };

            // If client don´t have any history start the ChildEventListener.
            // Typically this is the first time app starts or user have cleared data.
            if (ToyManager.getInstance().getHistoryItems(mFireBaseAuth.getCurrentUser().getUid()).size() == 0) {
                Log.i(TAG, "HistoryItems SIZE = 0 starting ChildEventListener");
                // Local cache of address history is empty get all address history for this user and start listen for new items
                final Query query = ref.child(USER_HISTORY).child(mFireBaseAuth.getCurrentUser()
                   .getUid())
                   .child(TOYS);
                mChildListenerMap.put(query.getRef(), userHistoryAddressChildEventListener);
                query.addChildEventListener(userHistoryAddressChildEventListener);

            } else {
                // If client have history then start the ValueEventListener.
                // Typically this is not the first time app starts.
                startListenForUserAddressHistory();
            }
            // [END Listen for history Address changes ]
        }

         private void userHistoryAddressChildEvent(DataSnapshot snapshot, String prevKey) {
            // get history for current user
            UserHistory.AddressHistory addressHistory = snapshot.getValue(UserHistory.AddressHistory.class);
            ToyManager.getInstance().addHistory(
                    mFireBaseAuth.getCurrentUser().getUid(),
                    addressHistory.getAddressId(),
                    addressHistory.getTime(),
                    addressHistory.getToy(),
                    addressHistory.getPushKey());
        }

     /**
         * Start listen for nye entries based on that server have entries<br>
         * and client have entries, typically this is not the first time App starts.
         * This uses a ValueEventListener.
         */
        private void startListenForUserAddressHistory() {
            // Local history is not empty so we must go get only new items
            final ValueEventListener listener = new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    // get history for current user
                    if (dataSnapshot.getChildrenCount() != 0) {
                        for (DataSnapshot child : dataSnapshot.getChildren()) {
                            UserHistory.AddressHistory addressHistory = child.getValue(UserHistory.AddressHistory.class);
                            if (dataSnapshot.getChildrenCount() == 1) {
                                // child count is one so this can be a SERVERTIME correctness call.
                                // skip the skipStartAtKey if key and time is the same.
                                if (addressHistory.getPushKey().equals(skipStartAtKey)) {
                                    // get historyItem
                                    HistoryItem historyItem = ToyManager.getInstance().getHistoryItem(mFireBaseAuth.getCurrentUser().getUid().concat(addressHistory.getPushKey()));
                                    // compare time
                                    if (historyItem.getTime().toString().equals(addressHistory.getTime().toString())) {
                                        Log.i(TAG, "time is the same exiting with return");
                                        return;
                                    } else
                                        Log.i(TAG, "time is different");
                                } else {
                                    Log.i(TAG, "PushKey not same as skipStartAtKey");
                                }

                            } else if (dataSnapshot.getChildrenCount() > 1) {
                                // two children or more so lets dump the skipStartAtKey and save the rest
                                Log.i(TAG, "TESTING  getChildrenCount > 1" + " skipStartAtKey " + skipStartAtKey + " time " + addressHistory.getTime());
                                if (addressHistory.getPushKey().equals(skipStartAtKey)) {
                                    Log.i(TAG, "PushKey same as skipStartAtKey");
                                    continue;
                                }
                            }
                            ToyManager.getInstance().addHistory(
                                    mFireBaseAuth.getCurrentUser().getUid(),
                                    addressHistory.getAddressId(),
                                    addressHistory.getTime(),
                                    addressHistory.getToy(),
                                    addressHistory.getPushKey());
                        }
                        ValueEventListener v = mValueListenerMap.get(dataSnapshot.getRef());
                        Log.i(TAG, "removing ValueEventListener for");
                        dataSnapshot.getRef().removeEventListener(v);
                        startListenForUserAddressHistory();
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                    Log.w(TAG, "onCancelled" + databaseError.toException());
                     // TODO dont forget to remove reset listeners
                }
            };
            // get the latest history item
            HistoryItem historyItem = ToyManager.getInstance().orderHistoryByDateAndGetNewest(mFireBaseAuth.getCurrentUser().getUid());
            final Query query = ref.child(USER_HISTORY)
                    .child(mFireBaseAuth.getCurrentUser().getUid())
                    .child(TOYS)
                    .orderByKey().startAt(historyItem.getPushKey()); // start listen on the latest history
            mValueListenerMap.put(query.getRef(), listener);
            skipStartAtKey = historyItem.getPushKey();
            query.addValueEventListener(listener);
        }


         /**
         * App is closing or User has signed out
         * Called from both onClose() and userSignedOut()
         */
        private void closeFirebase() {
            userLogger.log(USER_SIGNED_OUT);

            // Close ChildEventListener(s)
            for (Map.Entry<DatabaseReference, ChildEventListener> entry : mChildListenerMap.entrySet()) {
                DatabaseReference ref = entry.getKey();
                ChildEventListener listener = entry.getValue();
                if (listener != null && ref != null)
                    ref.removeEventListener(listener);
            }
            // Close ValueEventListener(s)
            for (Map.Entry<DatabaseReference, ValueEventListener> entry : mValueListenerMap.entrySet()) {
                DatabaseReference ref = entry.getKey();
                ValueEventListener listener = entry.getValue();
                if (listener != null && ref != null)
                    ref.removeEventListener(listener);
            }
            // Close
            if (userValueEventListener != null)
                ref.child(USER).child(mFireBaseAuth.getCurrentUser().getUid())
                        .removeEventListener(userValueEventListener);
            if (userAuthListener != null)
                mFireBaseAuth.removeAuthStateListener(userAuthListener);
            userLogger = null;


            }
Comments