Firebase by default orders data from the earliest and I need it to be ordered from the latest.
I am using timestamp to do so and doesn't seem to be working.
private void filldata() {
mDatabase.child("Data").orderByChild("timestamp").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot snapshot, String s) {
System.out.println("snapshot:" + snapshot.toString());
}
}
You no need to use orderByChild() here in your case because firebase itself generate unique key which is based on a timestamp, so you can simply use orderByKey() in your query and you will get your data in latest order.
The unique key is based on a timestamp, so list items will
automatically be ordered chronologically. Because Firebase generates a
unique key for each blog post, no write conflicts will occur if
multiple users add a post at the same time.
You can find more here
I'll suggest to use
mDatabase.child("Data").orderByKey().limitToLast(no_of_items_you_want)
This will give you list of latest data
Also to get value from snapshot use
snapshot.getValue(String.class);
Since orderByChild() only sort data in ascending order, you should store an extra data item in your child node whith the value timestamp*(-1) and then sort (order) on this data item.
Your code is correct. The commonly suggested way to order will be by using a negative timestamp.
However I have noticed previously that firebase does order your results by timestamp, as you currently wish for it to do. When the device receives the results it reorders the results by arrival (suspicion).
To test this, try limit your results by using the .limitToLast(n) function, you will realize that while firebase will return the last 10 (in order of timestamp) results to you, these results will not be ordered by timestamp.
Therefore, the best solution will be to store the firebase results in a list and reorder the list using a sorting tool like a comparator
Related
I am developing an Android chat application in which I need to order the conversation details by the date. My firebase data structure is mentioned below.
Now I want to retrieve and show the data on the latest date on my RecyclerView from Firebase Realtime Database based on timestamp.
I have tried the following approaches.
final DatabaseReference nm =
FirebaseDatabase.getInstance().getReference("Transaction");
Query query = nm.orderByChild("Date").limitToFirst(5);
;
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
listData.clear();
if (dataSnapshot.exists()) {
for (DataSnapshot npsnapshot : dataSnapshot.getChildren()) {
Transaction ld = npsnapshot.getValue(Transaction.class);
listData.add(ld);
}
Tadapter = new TransactionAdapter(listData);
rv.setAdapter(Tadapter);
Log.d(TAG, "Total Count" + Tadapter.getItemCount());
}
}
}
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?
Query query = nm.orderByChild("Date").limitToFirst(5);
Firebase realtime database sorts in ascending order that means those 5 nodes that you'll receive will be the oldest.
I want to retrieve and show the data in latest date
Try using limitToLast instead which will return the last 5 documents after ordering the nodes by Date field i.e. the 5 latest nodes.
Query query = nm.orderByChild("Date").limitToLast(5);
You can read more about that at sorting and filtering data.
I want to query my Workout Collection for the latest workout from a routine. Meaning I query with whereEqualTo my routineKey, order it by the Started TimeStamp in descending order and then limit to 1 and then take the this 1st Key/Id of the Workout.
However this does not work. whereEqualTo and orderBy work separately but not combined. What am I doing wrong?
fm.getColRefWorkout().whereEqualTo("routineKey", routineKey).orderBy("startTimeStamp", Query.Direction.DESCENDING).limit(1).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
workoutKey = documentSnapshots.getDocuments().get(0).getId();
//To stuff with this workoutKey
}
});
This query will not work unless you create an index for it. This can be done, by creating it manually in your Firebase Console or if you are using Android Studio, you'll find in your logcat a message that sounds like this:
FAILED_PRECONDITION: The query requires an index. You can create it here: ...
You can simply click on that link or copy and paste the URL into a web browser and your index will be created automatically.
I've an a firebase recyclerview and I want to query that datas in a OrderByChild for example TOPWEEK or TOPDAYS in order to that I planning to combin ServerValue.TIMESTAMP with star counts such as
"Combin" : "1522741072_5"
first value is timestamp second value is star counts. but if I made this every time new one goes top, star counts is ignored (because of timestamp is in mili sec). I thinking that I should trim some value from timestamp. like this:
String.valueOf(ServerValue.TIMESTAMP).substring(0,4)
but it is not possible because I cant store timestamp as a string in firebase database. this is my model class
#Exclude
public Map<String, Object> haritala() {
HashMap<String, Object> result = new HashMap<>();
result.put("yazar", yazar);
result.put("baslik", baslik);
result.put("uid",uid);
result.put("favsays", favsays);
result.put("fav", favori);
result.put("mesajsays", mesajsays);
result.put("mesaj", mesaj);
result.put("Combin", ServerValue.TIMESTAMP);
return result;
}
Are there any solution
According to your last comment, I understood that the star counts does not contains a fixed value, it can be incremented by users. In this case, your solution will not work. There is another solution to have two separate properties but unfortunately, Firebase Realtime database does not support queries on multiple properties, supports only queries on a single child property. Also you should not consider augmenting your data structure to allow a reverse lookup because in that case you'll have to many nodes.
If I were you, every time I should add a new item to the database, I'll use the push() method, which will generate as the key of the item, a random key which is based on time. So by default, all your items will be sorted by creation time. In this case, you'll only need to use a query that will look like this:
Query query = rootRef.child("results").orderByChild("reuslt");
Don't forget to set the value of result property as an Integer or as a Long, not as a String because in case of string the items are ordered lexicographically.
You can consider take a look at Cloud Firestore, in which chained queries are permitted.
If we query data from Firebase on a key for a child node, does it downloads the whole child node and filter data in the application or it downloads the query specific data? i.e. the filtered data
String myUserId = getUid();
Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId).orderByChild("starCount");
myTopPostsQuery.addChildEventListener(new ChildEventListener() {});
myTopPostsQuery will sort data according to starCount and I will receive data in the addChildEventListener() I want to know that whether this data is being filtered inside my app after receiving or my app downloads only the filtered data from the Firebase.
If you use a filter in your query you will download the query specific data without any operation executed on the client side.
Keep in mind that:
You can only use one order-by method at a time. Calling an order-by method multiple times in the same query throws an error.
You can combine multiple limit or range functions. For example, you can combine the startAt() and endAt() methods to limit the results to a specified range of values.
For any other info take a read here
You get the data already filtered. When you use a query, let say, limitToLast(10) you get only those 10 elements. This is happening also in your case with orderByChild("starCount"). In your SnanpShot will find only those filtered elements. Please visit official doc for more details.
Hope it helps.
Based on the code you pasted here, your query will just retrieve all the posts for the database path user-posts/<id> with an ordered manner which means that there is not filter. But still you will get back all the available posts under the path you are querying. It can be a "semi-filter" as it will find only the posts which include starCount field
The best thing is to filter during your query in order to retrieve back exactly what is needed and not everything as you are doing right now, imagine that this list of posts can be really big so you will have a big issue with performance later.
Read the following section here about sorting & filtering.
https://firebase.google.com/docs/database/admin/retrieve-data#orderbychild
Apart from that consider to add an index in userId field for speeding up your query.
I'm trying to migrate an app I had built which used Parse as its cloud backend. In my Parse backend database, I had a table which stored data as shown below:
Device ID | Contacts
xxxxx001 | "(800)-888-8888"
xxxxx002 | "(800)-888-8858"
xxxxx003 | "(800)-888-8868"
Over here, device ID is the android device ID and the Contacts are an ArrayList of strings which was generated through logic on the device. Basically, the user would select a contact (multiple in future iterations, hence it being an ArrayList, for testing I'm just keeping one item in the list) and that contact is saved for that DeviceID in the backend database. If the same DeviceID changes the contact, the contacts ArrayList in the database corresponding to its DeviceID would be replaced with the new ArrayList.
I'm trying to get something similar set up on Firebase, however right now it seems I only have a global variable on my databse which seems to get updated each time I press my button.
Here is my code for the button:
DatabaseReference mRootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference mContactsRef = mRootRef.child("contacts");
#Override
protected void onStart() {
super.onStart();
mButtonContactSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mContactsRef.setValue(contacts); //contacts is an arraylist with 1 item
}
});
}
Here is how it looks in Firebase after clicking the button 3 times:
Instead of updating the value, it seems to add another row(?) of to store the current phone number selected. How can I go about setting up a DeviceID->(Objects to be stored per device)
sort of setup?
You're looking for push(), which generates a unique ID for new items.
From the Firebase documentation on reading and writing lists of data:
// Create a new post reference with an auto-generated id
var newPostRef = postListRef.push();
newPostRef.set({
// ...
});
The new items will have complex-looking keys of the form -KTTHEScy82fpfNSCoYN. Read this article on why those are preferred over array indices and (if you're interested) this article that explains the format of these keys.
Consider a different data model
In general though you might want to consider a different data model. What you're storing is a collection of phone numbers. At first sight, storing those in an array-like list seems fine.
But typically you'll want these behaviors for this contact list:
each phone number can only be present once
you need to find whether a given phone number is already in the list
With your current structure you can only see if a number is already in the list by scanning all items in the list. Whenever that is the case, it is a good moment to consider using a set data structure instead.
In Firebase you'd model a set of phone numbers like this:
"contacts": {
"(800)-888-8858": true
"(800)-888-8868": true
"(800)-888-8888": true
}
While this structure initially looks less efficient, it is actually stored more efficiently than the array list in Firebase. And looking up whether an item exists is now a simple existence check instead of having to scan the array. And with this structure it is impossible to store the same number twice.