Skip to content Skip to sidebar Skip to footer

Firebase Use Endat If Timestamp Field

I have records with this fields: age: 25 timestamp: 1484089199472 This records inserted by: @Exclude public Map toMap() { HashMap r

Solution 1:

You should order your nodes by the timestamp child first and secondly order the received items by points on the client side. This was described here.

I would suggest you to use this query instead:

@OverridepublicQuerygetQuery(final DatabaseReference databaseReference) {
    Date endTime = newDate();
    endTime.setHours(23);
    endTime.setMinutes(59);
    endTime.setSeconds(59);

    return databaseReference.child("toplist").orderByChild("timestamp")
            .endAt(endTime.getTime()).limitToFirst(50);
}

This way you are telling Firebase to sort your nodes by one of their child nodes which in this case would be timestamp. Hope this helps.

Next you would need to sort your data on the client side. A problem of this would be that realtime changes from firebase would not reorder your items inside a RecyclerView for example.

Once again I recommend reading through this answer.

Solution 2:

I solved this problem after days with experiments.

The point is,

I'm surprised to found out even query can be ordered by deep nested children, but it works for children ONE more level down only!

Being such circumstance, I tried to go for node one more level down first and do query for a specific period on it and it works.

This is my data tree on Firebase real time database: enter image description here

For reading my POJO models stored in Firebase, I set up a helper class serving for me. So I run FirebaseDatabaseHelper.getInstance().readCatalogFromDatabase(Card.class, listener, start, end); while time to update my UI with newest database.

About my FirebaseDatabaseHelper, there're two relative methods serving me well for reading models on the database reference() which refers to parent node holding lots of models like "/Card/user_id" node that has bunches of children meaning card details at /Card/user_id/card_id".

/**
 * attaches listener to obtain values at child locations of "catalog/" storing lots of models in JSON tree
 * reads values created in a specific period and ordered by date
 *
 * catalog: "Card" for card
 *          "Comment" for comment
 *
 * It's surprised to found out even query can be ordered by deep nested children, but children ONE more level down only
 * Being such circumstance, go for node one more level down first and do query for a specific period on it
 */publicvoidreadCatalogFromDatabase(final Class<?> clazz, final OnReadDatabaseChildEventListener child_listener, final long start, final long end) {
    //Logger.d(">>> end at date before:" + (end/(1*24*60*60*1000) - start/(1*24*60*60*1000)));Logger.d(">>> start:" + start + ", end:" + end);
    DatabaseReference referenceCatalog;
    OnReadDatabaseValueEventListener ids_listener;
    String catalog;
    if (clazz.getName().equals(Card.class.getName())) {
        ids_listener = newOnReadDatabaseValueEventListener() {
            @OverridepublicvoidonDataChange(DataSnapshot dataSnapshot) {
                List<String> ids = newLinkedList<>();
                Logger.d("... user count:" + dataSnapshot.getChildrenCount());
                /**
                 * $ROOT/catalog/user_id/CardId/CardId
                 * $ROOT/catalog/user_id/CardId/ProfilePhoto
                 * $ROOT/catalog/user_id/CardId/ProfileTitle
                 * $ROOT/catalog/user_id/CardId/ProfileName
                 * $ROOT/catalog/user_id/CardId/ProfileID
                 * $ROOT/catalog/user_id/CardId/ArticleTitle
                 * $ROOT/catalog/user_id/CardId/ArticleContent
                 * $ROOT/catalog/user_id/CardId/ArticleCount
                 * $ROOT/catalog/user_id/CardId/ArticlePhoto
                 * $ROOT/catalog/user_id/CardId/ArticlePhotoFileName
                 * $ROOT/catalog/user_id/CardId/Distance
                 * $ROOT/catalog/user_id/CardId/Date
                 *      ^[key]  :[value]                -> initial
                 *              ^[key]  :[value]        -> 1th for-loop
                 */for (DataSnapshot snapShotOfUserId : dataSnapshot.getChildren()) {
                    Logger.d("... user(" + snapShotOfUserId.getKey() + ") post count:" + snapShotOfUserId.getChildrenCount());
                    ids.add(snapShotOfUserId.getKey());
                }
                for (String id : ids) readListFromDatabase(clazz, id, child_listener, start, end);
                FirebaseDatabaseHelper.getInstance().detachValueEventListener(this);
            }

            @OverridepublicvoidonCancelled(DatabaseError databaseError) {
                child_listener.onCancelled(databaseError);
                FirebaseDatabaseHelper.getInstance().detachValueEventListener(this);
            }
        };
        catalog = Card.class.getSimpleName();
        referenceCatalog = getDatabaseChild(catalog, null, null);
        referenceCatalog.orderByKey().limitToLast(COUNT_ON_PAGE).addListenerForSingleValueEvent(ids_listener);
        mValueEventListeners.put(ids_listener, referenceCatalog);
    } elseif (clazz.getName().equals(Comment.class.getName())) {
        ids_listener = newOnReadDatabaseValueEventListener() {
            @OverridepublicvoidonDataChange(DataSnapshot dataSnapshot) {
                List<String> ids = newLinkedList<>();
                Logger.d("... card count:" + dataSnapshot.getChildrenCount());
                /**
                 * $ROOT/catalog/card_id/CommentId/CardId
                 * $ROOT/catalog/card_id/CommentId/CommentId
                 * $ROOT/catalog/card_id/CommentId/ProfilePhoto
                 * $ROOT/catalog/card_id/CommentId/ProfileName
                 * $ROOT/catalog/card_id/CommentId/ProfileID
                 * $ROOT/catalog/card_id/CommentId/Comment
                 * $ROOT/catalog/card_id/CommentId/Distance
                 * $ROOT/catalog/card_id/CommentId/Date
                 *      ^[key]  :[value]                    -> initial
                 *              ^[key]  :[value]            -> 1th for-loop
                 */for (DataSnapshot snapShotOfCardId : dataSnapshot.getChildren()) {
                    Logger.d("... card(" + snapShotOfCardId.getKey() + ") comment count:" + snapShotOfCardId.getChildrenCount());
                    ids.add(snapShotOfCardId.getKey());
                }
                for (String id : ids) readListFromDatabase(clazz, id, child_listener, start, end);
                FirebaseDatabaseHelper.getInstance().detachValueEventListener(this);
            }

            @OverridepublicvoidonCancelled(DatabaseError databaseError) {
                child_listener.onCancelled(databaseError);
                FirebaseDatabaseHelper.getInstance().detachValueEventListener(this);
            }
        };
        catalog = Comment.class.getSimpleName();
        referenceCatalog = getDatabaseChild(catalog, null, null);
        referenceCatalog.orderByKey().limitToLast(COUNT_ON_PAGE).addListenerForSingleValueEvent(ids_listener);
        mValueEventListeners.put(ids_listener, referenceCatalog);
    }

and go to,

/**
 * attaches listener to obtain values at child locations of "catalog/id/" storing list of models in JSON tree
 * reads values created in a specific period and ordered by date
 *
 * id: user id for card
 *     card id for comment
 *
 * query can be ordered by deep nested ONE more level down children
 */publicvoidreadListFromDatabase(Class<?> clazz, String id, OnReadDatabaseChildEventListener listener, long start, long end) {
    //Logger.d(">>> end at date before:" + (end/(1*24*60*60*1000) - start/(1*24*60*60*1000)));
    Logger.d(">>> start:" + start + ", end:" + end + ", id:" + id);
    DatabaseReference referenceCatalog;
    Query query;
    String catalog;
    if (clazz.getName().equals(Card.class.getName())) {
        catalog = Card.class.getSimpleName();
        referenceCatalog = getDatabaseChild(catalog, id, null);
        query = referenceCatalog.orderByChild("Date").startAt(start).endAt(end).limitToLast(COUNT_ON_PAGE);
        query.addChildEventListener(listener);
        mChildEventListeners.put(listener, referenceCatalog);
    } elseif (clazz.getName().equals(Comment.class.getName())) {
        catalog = Comment.class.getSimpleName();
        referenceCatalog = getDatabaseChild(catalog, id, null);
        query = referenceCatalog.orderByChild("Date").startAt(start).endAt(end).limitToLast(COUNT_ON_PAGE);
        query.addChildEventListener(listener);
        mChildEventListeners.put(listener, referenceCatalog);
    }
}

about database reference,

/**
 * gets a database reference to location headed with "/catalog/", "/id/" and "/key/" as prefixes(to a child location in JSON tree)
 *
 * id: user id for card
 *     card id for comment
 * key:
 *     card id for card
 *     comment id for comment
 */privateDatabaseReferencegetDatabaseChild(String catalog, String id, String key) {
    Logger.d(">>>");
    DatabaseReference reference;
    if (catalog == null) {
        if (id == null) {
            if (key == null) {
                Logger.d("... catalog:" + catalog + ", id:" + id + ", key:" + key);
                reference = FirebaseDatabase.getInstance().getReference();
            } else {
                Logger.d("... catalog:" + catalog + ", id:" + id + ", key:" + key);
                reference = FirebaseDatabase.getInstance().getReference(key);
            }
        } else {
            if (key == null) {
                Logger.d("... catalog:" + catalog + ", id:" + id + ", key:" + key);
                reference = FirebaseDatabase.getInstance().getReference(id);
            } else {
                Logger.d("... catalog:" + catalog + ", id:" + id + ", key:" + key);
                reference = FirebaseDatabase.getInstance().getReference(id + "/" + key);
            }
        }
    } else {
        if (id == null) {
            if (key == null) {
                Logger.d("... catalog:" + catalog + ", id:" + id + ", key:" + key);
                reference = FirebaseDatabase.getInstance().getReference(catalog);
            } else {
                Logger.d("... catalog:" + catalog + ", id:" + id + ", key:" + key);
                reference = FirebaseDatabase.getInstance().getReference(catalog + "/" + key);
            }
        } else {
            if (key == null) {
                Logger.d("... catalog:" + catalog + ", id:" + id + ", key:" + key);
                reference = FirebaseDatabase.getInstance().getReference(catalog + "/" + id);
            } else {
                Logger.d("... catalog:" + catalog + ", id:" + id + ", key:" + key);
                reference = FirebaseDatabase.getInstance().getReference(catalog + "/" + id + "/" + key);
            }
        }
    }
    return reference;
}

That's the way I go query in a specific period.

Beside, I found some answers mentioned about people should call addChildEventListener() following orderByChild(); However, after running experiments, I say,

Query query;
query = referenceCatalog.orderByChild("Date").startAt(start).endAt(end).limitToLast(COUNT_ON_PAGE);
query.addChildEventListener(listener);

and

referenceCatalog.orderByChild("Date").startAt(start).endAt(end).limitToLast(COUNT_ON_PAGE).addChildEventListener(listener);

They are same.

I deem their difference to just the way people program in Java with anonymous class or not.

Post a Comment for "Firebase Use Endat If Timestamp Field"