Database snapshot
This is my fire base database (the image attached by the link ). I want to sort all these by the date. As you can see in the image, I've made a date variable. So for a date, "20 May 2018", the date variable has the value "20180520" . Hence, sorting the data by simply the integer value of date will do the job. The code I used for showing these data is,
DatabaseReference mDatabase= FirebaseDatabase.getInstance().getReference();
mDatabase.addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
map = (Map<String, Object>) dataSnapshot.getValue();
itr = map.entrySet().iterator();
entry = itr.next();
Map singleUser = (Map) entry.getValue();
String name=(String) singleUser.get("name");
String d=(String) singleUser.get("sdate");
String m=(String) singleUser.get("smon");
String y=(String) singleUser.get("syear");
String Submi=(String) singleUser.get("subm");
Now, I want this code to be manipulated in such a manner that the data appears in the increasing order of date. How can I sort the firebase ? And if it's not possible, how can I sort the Map(String,Object) by Object.date ?
Please help
You are able to sort the retrieved data from the server. Please take a look at this part of the documentations - Ordering by a specified child key.
In your case it's gonna look something like this:
final DatabaseReference usersRef = database.getReference("users");
usersRef.orderByChild("date").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Your code goes here...
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}});
If you want to order your database items by date you should store the date as a ServerValue.TIMESTAMP as explained here and not as number as I see in your screenshot.
So the ServerValue.TIMESTAMP is just a token that the server understands and translates to a number, which is the current time using its own clock.
If you're trying to store the date as numbers or strings in Realtime Database, don't. That's not a very good solution.
Related
Basically what I am trying to do is I have a database with the name users having an attribute username. I have some usernames in one list and I want to show details of these users only whose username is present in the list. How can I write a query to fetch details of those users only whose username is found in this list? And note that there is no lexicographical ordering so i can't use startAt() and endAt() functions as well.
code snippet:
=> myList contains usernames. This code doesn't yield accurate results.
Any help would be really appreciated! Thank you!
FirebaseRecyclerOptions<MainModel> options =
new FirebaseRecyclerOptions.Builder<MainModel>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username")
.startAt(myList.get(0)).endAt(myList.get(myList.size()-1)),MainModel.class).build();
As already mentioned in the comment, the Firebase-UI library doesn't help in your case, because it doesn't allow you to pass multiple queries to the FirebaseRecyclerOptions object. So you need to perform a separate query and use the combined result.
When you are calling .get() on a Firebase Realtime Database query object, you are getting back a Task object. So the key to solving this problem is to use whenAllSuccess(Collection> tasks). In your case, it should look like this:
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = db.child("users");
Query query = usersRef.orderByChild("username");
List<Task<DataSnapshot>> tasks = new ArrayList<>();
for (String username : myList) {
tasks.add(query.equalTo(username).get());
}
Tasks.whenAllSuccess(tasks).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
#Override
public void onSuccess(List<Object> list) {
//Do what you need to do with your list.
for (Object object : list) {
MainModel mm = ((DataSnapshot) object).getValue(MainModel.class);
if(mm != null) {
Log.d("TAG", mm.getUsername());
}
}
}
});
Assuming that you have in your MainModel class a getter called getUsername(), the result in your logcat will be all the usernames of all returned children.
I am trying to retrieve data from Firebase depending on the position. If I don't know, what the key of the first value is like, how am I able to access the value of the first position?
ticketCodes.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
GenericTypeIndicator<List<String>> t = new GenericTypeIndicator<List<String>>() {};
List<String> yourStringArray = dataSnapshot.getValue(t);
// Here I want to receive the value of the first index in firebase without knowing what the key is.
//I am not able to. Though if I put "get(firstKey)" it gives me the value of the first index.
String value = yourStringArray.get(0);
Is there another way of how to get access of the first position in this List?
My database looks like the following:
Hey I would like to sort time stored in firebase database as string in the ascending order and display it in a list. I have found solutions regarding sorting integer values.
This is my database where I would like to sort according to the timeTaken by each user id at that specific question id.
Edit:
So my question is how can I retrieve the data from the each users uid of that specific time taken on that question id (here:982906) and sort that list to retrieve who solved the problem in the least time.
private void getTimeTaken() {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("users");
Query query = databaseReference.orderByChild("questions").startAt("982906");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
yourTimeArraylist = new ArrayList<>();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
UserPuzzleDetails userPuzzleDetails = postSnapshot.getValue(UserPuzzleDetails.class);
yourTimeArraylist.add(new UserPuzzleDetails(userPuzzleDetails.getYourAnswer(), userPuzzleDetails.getAnswerScore(), userPuzzleDetails.getTimeTaken()));
Log.e("", " " + userPuzzleDetails.getTimeTaken());
}
for (int i = 0; i < yourTimeArraylist.size(); i++) {
UserPuzzleDetails user = yourTimeArraylist.get(i);
Log.d("test your rank", " onDataChange: " + user.getTimeTaken() + " " + user.getAnswerScore());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I have changed the values of time in the database as int in milliseconds but am unable to understand how to sort the values of question id 982906 acording to the time taken . I have tried the above method which is returning 0 everytime.
A Firebase Database filters the children immediately under the location that you query, based on a single property (or other condition) that you specify. The query cannot be based on a dynamic path under the child nodes.
You're nesting data in a way that doesn't allow this query: each answer is one dynamic level deeper in the tree: `/users/$uid/questions/$qid". This is one of the many reasons why the Firebase documentation recommends against nesting data in this way.
If you want to query a list of answers across all users by their "time taken", you should store precisely that in your database: a list of answers, each with their "time taken".
questionAnswers
$questionId
$uid
timeTaken: "08:17:23.6"
Now you can get the 10 fastest answer for question 42 with:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference answersReference = databaseReference.child("42");
Query query = answersReference.orderByChild("timeTaken");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot userAnswerSnapshot: dataSnapshot.getChildren()) {
System.out.println("User "+userAnswerSnapshot.getKey()+" took "+userAnswerSnapshot.child("timeTaken").getValue());
}
}
You can achieve that by creating a Data model of Answer and use comparator to sort the items by comparing dates.
Collections.sort(listItemAnswer, new Comparator<AnswerInfoDto>() {
#Override public int compare(AnswerInfoDto l, AnswerInfoDto r)
{ // Compare l.timeTaken and r.timeTaken} }
Edit To match with your case, you will have to parse the time string with SimpleDateFormat before comparing dates as below :
class StringDateComparator implements Comparator<String>
{
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
public int compare(String lhs, String rhs)
{
return dateFormat.parse(lhs).compareTo(dateFormat.parse(rhs));
}
}
Collections.sort(arrayList, new StringDateComparator());
My Firebase Database is like this
When the coding below was run:
String loc=(snapshot.child("loc").getvalue()).tostring();
The output I get has different sequence with the database:
Why is that so?
Firebase data is stored as JSON and is inherently unordered.
If you want to access the data in a specific order, you should specify an orderBy clause for your query and access the data using the snapshot's getChildren() method.
Say you want to log the items by ascending key:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getRef();
Query locations = rootRef.orderByKey();
locations.addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot locSnapshot: snapshot.getChildren()) {
System.out.println(locSnapshot.getKey() + ": " + locSnapshot.getValue(String.class));
}
}
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
});
This sample comes (modified) from the Firebase documentation on reading lists of data.
Frank beat me to my edit, check out his correct solution using orderBy....
You need to use forEach rather than the child method (or child.foreach)
Here is a snippet from the doc:
Because of the way JavaScript Objects work, the ordering of data in
the JavaScript Object returned by val() is not guaranteed to match the
ordering on the server nor the ordering of child_added events. That is
where forEach() comes in handy. It guarantees the children of a
DataSnapshot will be iterated in their query-order.
Source: https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#forEach
As a newbie in firebase I tried to mimic a kind of "where clause" request to retrieve the user's wallet in this simple use case:
User
48bde8f8-3b66-40bc-b988-566ccc77335c
email: "toto#acme.com"
username: "userTest1"
UserWallet
F4PvtvNT2Z
coins: 26
someList
elemet1
elemet2
user: "48bde8f8-3b66-40bc-b988-566ccc77335c"
First I tried to code my request like this:
Firebase root = new Firebase("https://myApp.firebaseio.com/");
Firebase ref = root.child("UserWallet");
Query query = ref.equalTo("48bde8f8-3b66-40bc-b988-566ccc77335c", "user");
The result was null, So I wrote this query:
Query query = ref.orderByChild("user").equalTo("48bde8f8-3b66-40bc-b988-566ccc77335c", "user");
Result was null again. The only way to retrieve the wallet was with this query:
Query query = ref.orderByChild("user").equalTo("48bde8f8-3b66-40bc-b988-566ccc77335c");
So Should I have to always use en "orderByChild()" query before to use "equalTo()"?
And so, what is the purpose of the query "equalTo(String value, String key)" compare to "equalTo(String value) since only the second one works correctly?
There are some edge cases that don't need an orderBy...(), but in general you'll need an orderBy...() before a filtering operation (equalTo(), startAt(), endAt()).
I highly recommend that you first read the Firebase programming guide for Android (95% of it applies to regular Java too). A few hours spent in that guide, will save dozens of questions here. For example: this is the section on queries.
After reading that, you might also want to read this guide on NoSQL Data Modeling. It covers many common patterns in NoSQL data modeling and will help you realize early on that trying to map SQL queries to a NoSQL database is a logical idea, but seldom a good one.
My initial (without any idea on your use-cases, except for "I need to be able to find the wallets for a user") model:
UserWallet
"48bde8f8-3b66-40bc-b988-566ccc77335c"
"F4PvtvNT2Z"
coins: 26
someList
element1
element2
In the above model, I've inverted the Wallet and User under UserWallet, so that looking up the wallet(s) for a user becomes easier.
ref.child('UserWallet').child(auth.uid).addValueEventListener(...
Note that there is no query involved here, so loading will be equally fast no matter how many users you have in your database.
Or alternatively:
User
"48bde8f8-3b66-40bc-b988-566ccc77335c"
email: "toto#acme.com"
username: "userTest1"
Wallet
"F4PvtvNT2Z"
coins: 26
someList
element1
element2
UserWallet
"48bde8f8-3b66-40bc-b988-566ccc77335c"
"F4PvtvNT2Z"
Now we've complete flattened the structure. To determine the wallets of a user, you go to UserWaller/$uid and then load each wallet from Wallets/$walletid. It may be a bit more code, but it'll be extremely efficient (since there are no queries involved).
You can use nested Query for this.! if you have multiple random id you can easily compare them.!
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference.child("user");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// dataSnapshot is the "issue" node with all children with id 0
for (DataSnapshot issue : dataSnapshot.getChildren()) {
// do something with the individual "issues"
Query query = reference.child("user").child(dataSnapshot.getKey().equals(YourData)));
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});