Reputation: 441
I am storing data in Firebase storage.
Object Comment
with attribute timestamp
. When I push data from device to Firebase I'm populating timestamp
with currentTime and store in long
data type.
When I do retrieving the data with firebaseRef.orderByChild("timestamp").limitToLast(15)
result is not sorting how I expected.
I even played around with rules and no result:
{
"rules": {
".read": true,
".write": true,
".indexOn": "streetrate",
"streetrate": {
".indexOn": ".value"
}
}
}
I tried store timestamp
in String
data type, same issue.
Upvotes: 40
Views: 46091
Reputation: 837
The Current version of firebase will allow you the fetch the data by sorting it in descending order.
All you have to do is pass an optional bool flag to let the firebase to know to fetch the data in descending order.
Syntax
Query<Object?> orderBy(Object field, {bool descending = false})
Example
QuerySnapshot eventsQuery =
await ref.orderBy('DateTime', descending: true).get();
Thanks
Upvotes: 0
Reputation: 49
public static List<'YourModel> desireList= new ArrayList<>();
//Your Realtime Database Query on "ORDERBY","Name" or Key or etc.
@Override
public void onDataChange(DataSnapshot dataSnapshot)
{
desireList.clear();
List<YourModel>tempList = new ArrayList<>();//Create temp list Object.
for (DataSnapshot dataSnapshotList : dataSnapshot.getChildren())
{
tempList.add(new YourModel(
dataSnapshotList.child("Name").getValue() + "",
dataSnapshotList.getKey() + "",
dataSnapshotList.child("ORDERBY").getValue() + ""));
}
//Save object list in reverse order start.
for (int i =tempList.size(); i>0; i--)
{
desireList.add(tempList.get(i-1));
}
//Save object list in reverse order end.
tempList.clear(); //To clear memory only(not required.)
//Then update your adapter
yoursAdapter.notifyDataSetChanged();
}
Upvotes: 1
Reputation: 37
If you are passing an arraylist to the recyclerView you can do something like this:
FirebaseDatabase.getInstance().getReference().child("parent_id")
.child("id").orderByChild("count");
tpDBListener = tpDatabaseRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
tpUploads.clear();
for(DataSnapshot postSnapshot : snapshot.getChildren()){
newUpload pupload = postSnapshot.getValue(newUpload.class);
pupload.setKey(postSnapshot.getKey());
tpUploads.add(pupload);//add new object on end
//tpUploads.add(0,pupload);//add new object at beginning
}
tpAdapter.notifyDataSetChanged();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Toast.makeText(home.this, error.getMessage(),Toast.LENGTH_SHORT).show();
}
});
to flip the order so first is last and last is first I recommend when putting the value in the database putting it as 9999999999 and then -1 for what ever ordering you want then use the: if you are not ordeing them by a value or a child.
tpUploads.add(0, pupload);//add new object at beginning
if you want to order by a value this is the better approach and initialize it in db as 9999999999 and then -1 for its value
.orderBy("child_ID")
firebase will try to read each digit for example 1 is before 6 but 10 will also come before 6 because of the first digit. That is why I start off with 9999999999 as the starting value and decrease acordingly
Upvotes: 1
Reputation: 11
This is a client side solution , it will sort the data according to a specific child in firebase database after filling the list
Collections.sort(list, new Comparator<ModuleClass>() {
@Override
public int compare(ModuleClass module, ModuleClass t1) {
return Integer.compare(module.getViews(), t1.getViews());
}
});
Upvotes: 1
Reputation: 2414
As I understand there is no descending method, for default it is ascending only, but you can reverse it manually. For more information read an official documantation about sorting and filtering data of Realtime Database https://firebase.google.com/docs/database/android/lists-of-data#sorting_and_filtering_data
Upvotes: 0
Reputation: 838
Based on Himanshus answer but Im using kotlin and instead of the timestamp in the question Im ordering by score which should be similar. I'm not sure if firebase has an ascending or descending function but this is what ended working for me in my current project. I hope it will help someone else in the near future.
FirebaseFirestore.getInstance().collection("leaderboard")
.orderBy("score")
.addSnapshotListener { snapshot, exception ->
if (exception != null) {
Log.e("Exception:", "Could not retrieve scores ${exception.localizedMessage}")
}
if (snapshot != null) {
scores.clear()
for (document in snapshot.documents) {
val data = document.data
val name = data?.get("name") as? String
val score = data?.get("score") as? Number
val documentId = document.id
val newScore = Score(name, score, documentId)
scores.add(newScore)
}
scores.reverse()
scoresAdapter.notifyDataSetChanged()
}
}
This is what worked for me. Happy coding!
Upvotes: 1
Reputation: 101
You can simply just reverse the list (ListView or RecyclerView) that you are using.
Upvotes: 0
Reputation: 65
I found the current firebase version supports descending order sorting:
citiesRef.orderBy("name", "desc").limit(3)
https://firebase.google.com/docs/firestore/query-data/order-limit-data
Hope it helps
Upvotes: -1
Reputation: 3
It is very simple,Use -1,-2,-3, etc to store data in the firebase database.Now the data will be displayed in the reverse order in recyclerView.
-3
-2
-1
Upvotes: 0
Reputation: 1001
add a column namely timestamp with values (-1*System.currentTimeMillis())
and while fetching data use orderByChild("timestamp").limitToFirst(15)
or orderByChild("timestamp").limitToLast(15)
according to your requirement.
it is smartway to get data in sorted manner, as firebase has no rule for descending order.
Upvotes: 2
Reputation: 11
If you are doing it on web then you can push values in an array and then print the stored values in reverse order.
var a=[]; //declaring an array a.
var num=snapshot.numChildren(); //storing number of children in var num.
a.push(snapshot.val()); // pushing data in the array.
if (a.length==num){ //checking if length of array is same as number of children.
a.reverse(); //reversing the array elements.
for(i=0; i<num; i++){
a[i].name;//this will sort the data in descending order.
}
}
Upvotes: 1
Reputation: 606
Sorting child items by TIMESTAMP can be done using android.support.v7.util.SortedList
class post{
private Object time;
public Object getTime() {
return time;
}
public void setTime(Object time) {
this.time = time;
}
...//rest code}
SortedList<post> data;
data = new SortedList<post>(post.class, new SortedList.Callback<post>() {
@Override
public int compare(post o1, post o2) {
Long o1l = Long.parseLong(o1.getTime().toString());
Long o2l = Long.parseLong(o2.getTime().toString());
return o2l.compareTo(o1l);
}......//rest code
ref.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
mSwipeRefreshLayout.setRefreshing(true);
post p=dataSnapshot.getValue(post.class);
data.add(p);
}...// rest code
android.support.v7.util.SortedList
can also be used with RecyclerView
Upvotes: 1
Reputation: 34513
Swift 3:
let query = firebase.child(YourQueryPath).queryOrdered(byChild: YourQueryChild).queryLimited(toLast: YourLimit)
query.observeSingleEvent(of: .value, with: { (snapshot) in
// Reverse order here to get top **YourLimit** results in descending order
})
Upvotes: -1
Reputation: 677
I don't see any option to reverse the data. But One Brute way is to get the data.
List<ModelClass> mList=new ArrayList();
public void onDataChange(DataSnapshot dataSnapshot)
{
mList.clear();
for(DataSnapshot children: dataSnapshot.getChildren()){
ModelClass modelClass=children.getValue(ModelClass.class);
mList.add(modelClass);
}
Collections.reverse(mList);
Adapter.notifyDataSetChanged();
}
Upvotes: 23
Reputation: 2417
one good solution I find if you are using recycler view to render that data...
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
// And set it to RecyclerView
mRecyclerView.setLayoutManager(mLayoutManager);
it will reverse the data rendering...
private static class ChatMessageViewHolder extends RecyclerView.ViewHolder {
TextView messageText;
TextView nameText;
public ChatMessageViewHolder(View itemView) {
super(itemView);
nameText = (TextView)itemView.findViewById(android.R.id.text1);
messageText = (TextView) itemView.findViewById(android.R.id.text2);
}
}
FirebaseRecyclerViewAdapter<ChatMessage, ChatMessageViewHolder> adapter;
ref = new Firebase("https://<yourapp>.firebaseio.com");
RecyclerView recycler = (RecyclerView)
findViewById(R.id.messages_recycler);
recycler.setHasFixedSize(true);
//////////////////////////////////////////////////////////
mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setReverseLayout(true);
mLayoutManager.setStackFromEnd(true);
recycler.setLayoutManager(mLayoutManager);
/////////////////////////////////////////////////////////
adapter = new FirebaseRecyclerViewAdapter<ChatMessage, ChatMessageViewHolder>(ChatMessage.class, android.R.layout.two_line_list_item, ChatMessageViewHolder.class, mRef) {
public void populateViewHolder(ChatMessageViewHolder chatMessageViewHolder, ChatMessage chatMessage) {
chatMessageViewHolder.nameText.setText(chatMessage.getName());
chatMessageViewHolder.messageText.setText(chatMessage.getMessage());
}
};
recycler.setAdapter(mAdapter);
Upvotes: 19
Reputation: 161
Sort at client side is simple and not require more system resources. Each data snapshot has previousChildkey field. If you want to desc sorting, imagine previousChildkey is nextChildKey. Here are my sample:
class LessonFirebaseArray<ObjectModel>{
private ArrayList<ObjectModel> mItems;
...
public LessonFirebaseArray() {
mItems = new ArrayList<>();
}
public int addItem(ObjectModel item, boolean isReverse){
int index;
if (item.getPreviousChildKey() != null) {
index = getIndexForKey(item.getPreviousChildKey());
if (index < 0) {
index = mItems.size();
}else if(index>0 && !isReverse) {
index = index + 1;
}
}else{
index = mItems.size();
}
mItems.add(index, item);
notifyInsertedListeners(index);
return index;
}
private int getIndexForKey(String key) {
int index = 0;
for (ObjectModel snapshot : mItems) {
if (snapshot.getKey().equals(key)) {
return index;
} else {
index++;
}
}
return -1;
}
private void notifyInsertedListeners(int index) {
if (mListener != null) {
mListener.onInserted(index);
}
}
}
Upvotes: 0
Reputation: 376
The @Monet_z_Polski approach, based on
@Override
public T getItem(int position) {
return super.getItem(getCount() - (position + 1));
}
does have a weird effect on not update FirebaseRecyclerView automatically (PopulateViewHolder is not triggered in realtime changes). So, the best option is use a negative key to index the data.
Upvotes: 5
Reputation: 366
I have solved problem by extending FirebaseListAdapter and overriding getItem method:
public abstract class ReverseFirebaseListAdapter<T> extends FirebaseListAdapter<T> {
public ReverseFirebaseListAdapter(Activity activity, Class<T> modelClass, int modelLayout, Query ref) {
super(activity, modelClass, modelLayout, ref);
}
public ReverseFirebaseListAdapter(Activity activity, Class<T> modelClass, int modelLayout, DatabaseReference ref) {
super(activity, modelClass, modelLayout, ref);
}
@Override
public T getItem(int position) {
return super.getItem(getCount() - (position + 1));
}
}
Upvotes: 10
Reputation: 598775
Firebase can order the items in ascending order by a given property and then returns either the first N items (limitToFirst()
) or the last N items (limitToLast()
). There is no way to indicate that you want the items in descending order.
There are two options to get the behavior you want:
Use a Firebase query to get the correct data, then re-order it client-side
Add a field that has a descending value to the data
For the latter approach, it is common to have a inverted timestamp.
-1 * new Date().getTime();
Upvotes: 71