Sort Data to Recyclerview Based on Latest Date from Firebase

Sort data to RecyclerView based on latest date from Firebase

I am developing an android chat application in which I need to order the conversation details by the date.

As I see in your screenshot, your Date property is of type String. This means that you cannot call:

.orderByChild("Date")

And expect to behave as it was a Timestamp. When you order String elements, the order that you get is always lexicographically. This means that Strings doesn't consider any sort of numeric values when sorting, especially when it comes to the dates, even if the dates contain numbers, as your first element does:

Date: "30/7/2021"

So using String values when querying your database it's not an option. However, I see you already have a Timestamp property. Maybe on that property, it was supposed to do the ordering. If that was not the case, I suggest you change the type of the Date property from String to Timestamp, as explained in my answer from the following post:

  • How to save the current date/time when I add new value to Firebase Realtime Database

Now I want to retrieve and show the data on the latest date on my RecyclerView

This means that most likely you need to reverse the order, meaning that all your transactions have to be displayed in your RecyclerView descending. In this case, there are a few options that you have, either on the server or on the client.

Assuming that you have changed the type of your Date property from String to Timestamp, then you can simply consider storing an inverted Timestamp value like this:

Firebase-root
|
--- transactions
|
--- 1
|
--- Date: 1627714194
|
--- invertedDate: -1627714194

See, the invertedDate property holds a negative value. Since by default, the elements are ordered ascending, to be able to order the transaction desecendiong, you should simply use:

Query query = nm.orderByChild("invertedDate").limitToFirst(5);

On the other hand, there are some workarounds that can be made to achieve the same thing on the client, as explained in my answer from the following post:

  • How to arrange firebase database data in ascending or descending order?

FirebaseRecyclerPagingAdapter - sort list by date

You can use a query to order the items by their timestamp value

val baseQuery: Query = FirebaseDatabase.getInstance().reference.child("news")
val orderedQuery: Query = baseQuery.orderByChild("timestamp")

This will give you the items in ascending order, so you will have to reverse them in your application code.

If you don't want to do that, consider storing an inverted timestamp value in your data:

"news" : {
"-MXJ0Fbmvewl3zZ6-Ugn" : {
"timestamp" : 1617108780000,
"inverted_timestamp" : -1617108780000,
"description" : "A Red Bull tem a ......Continue lendo",
"id" : "-MXJ0Fbmvewl3zZ6-Ugn",
"thumb" : "https://cdn-1.motorsport.com/images/amp/YpNW51X0/s6/formula-1-bahrain-gp-2021-max--2.jpg",
"title" : "F1: Red Bull deve estar ainda melhor na etapa de Ímola; saiba mais",
"url" : "http://motorsport.uol.com.br/f1/news/f1-red-bull-deve-estar-ainda-melhor-em-imola-entenda-os-detalhes/5991023/?utm_source=RSS&utm_medium=referral&utm_campaign=RSS-ALL&utm_term=News&utm_content=br"
},
"-MXJ0LxzjUjfGFDvamKE" : {
"timestamp" : 1617118680000,
"inverted_timestamp" : -1617118680000,
"description" : "As mudanças nas ...Continue lendo",
"id" : "-MXJ0LxzjUjfGFDvamKE",
"thumb" : "https://cdn-1.motorsport.com/images/amp/YBeqJen2/s6/lance-stroll-aston-martin-amr2.jpg",
"title" : "Análise técnica: entenda como as equipes de F1 responderam ao desafio do assoalho de 2021",
"url" : "http://motorsport.uol.com.br/f1/news/analise-tecnica-entenda-como-as-equipes-de-f1-responderam-ao-desafio-do-assoalho-de-2021/5992503/?utm_source=RSS&utm_medium=referral&utm_campaign=RSS-ALL&utm_term=News&utm_content=br"
},
}

With the above data structure, you can then get them items in descending order with:

val orderedQuery: Query = baseQuery.orderByChild("inverted_timestamp")

You can then pass the orderedQuery to the adapter, to see the items based on their descending timestamp.

How to sort my RecyclerView according to date and time

Change make following changes to your AppointmentData

public class AppointmentData {
// ...
private Object date;
// ...
public void setDate(Object date) {
this.date = date;
}
// ...
public AppointmentData(String name, String tel, String address, String time, Object date) {
// ...
}
// ...
public Object getDate() {
return date;
}
}

Change db to this:

Query db = FirebaseDatabase.getInstance().getReference().child("Email").child(mCurrentUser.getUid()).child("Appointment").orderByChild("date");

Change this line inside populateViewHolder to this: viewHolder.dateApp.setText(timestampToDateString(model.getDate()));

where timestampToDateString is a utility method:

public static String timestampToDateString(long timestamp){
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
Date date = new Date(timestamp);
return dateFormat.format(date);
}

change btnSave.onClickListener to this

    final String key = FirebaseDatabase.getInstance().getReference().child("Email").child(mCurrentUser.getUid()).child("Appointment").push().getKey();

// ...
Long date = mSelectedDate;
// ...
AppointmentData appointmentData = new AppointmentData(name, tel, address, time, date);

FirebaseDatabase.getInstance().getReference().child("Email").child(mCurrentUser.getUid()).child("Appointment").child(key).setValue(appointmentData);
// ...

add the field like so

private long mSelectedDate;

initialize it in datePic() like so

    // ...
mYear = c.get(Calendar.YEAR);
// ...
mSelectedDate = fieldToTimestamp(mYear, mMonth, mDay);

and in onDateSelectedListener.onDateSet(...) like so

// ...
mSelectedDate = fieldToTimestamp(year, monthOfYear, dayOfMonth);

where fieldToTimestamp is helper method

private long fieldToTimestamp(int year, int month, int day) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
return (long) (calendar.getTimeInMillis() / 1000L);
}

I think that should be all of it.. Oh, and delete all your old Appointments so it doesn't cause exceptions.

Guaranteed order of fetched data from Firebase Realtime Database

What is the order of data when I fetch from my Firebase Realtime Database without using any orderBy methods?

If you are looking to have your elements ordered even if you don't use a call to orderBy(), then you should use the pushed IDs provided by the DatabaseReference#push() method. These pushed IDs aren't actually timestamps but they contain a time component. As Michael Lehenbauer mentioned in this blog article:

Push IDs are string identifiers that are generated client-side. They are a combination of a timestamp and some random bits. The timestamp ensures they are ordered chronologically, and the random bits ensure that each ID is unique, even if thousands of people are creating push IDs at the same time.

And to answer your second question:

If I use the get(), is it always 100% guaranteed that the data I will get is sorted from oldest to the newest or will it be in lexicographical order?

It doesn't matter if you add a ValueEventListener or ChildEventListener or even if you call Query#get(), the results will be ordered in the same way.

However, if you need to explicitly have an order according to a time component, then you should add a property of type "timestamp", as explained in my answer from the following post:

  • How to save the current date/time when I add new value to Firebase Realtime Database

If you want to reverse the order please check the following answer:

  • Sort data to RecyclerView based on latest date from Firebase


Related Topics



Leave a reply



Submit