I am new in firebase, I want to sort data, by timestamp and my database is below, here key is timestamp
My code for retrieving data is below
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("MainDoor");
Query dataOrderedByKey = myRef.orderByChild("{pushId}/key");
dataOrderedByKey.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, MyListData> value = ((HashMap<String, MyListData>) dataSnapshot.getValue());
Here i am getting value is not by order of key
I am getting data like below which is not in sort order
Data in a Map is by definition not sorted. So when you call dataSnapshot.getValue(), all information about the order of the items in the DataSnapshot is list.
To maintain the order, use a data structure that supports that, such as a list, and extract the individual items in the correct order by looping over DataSnapshot.getChildren().
So something like:
dataOrderedByKey.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
System.out.println(snapshot.getKey());
MyListData value = snapshot.getValue()
}
}
...
Also you can get data from firebase in sorted order . Refer my answer at Sort Firebase data in ascending/Descending Order
You want to sort by date, right? Try it
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("MainDoor");
myRef.orderByChild('date').addChildEventListener(new ChildEventListener() {
// implement the ChildEventListener methods as documented above
});
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.
// Assume we have the following data in the Database:
{
"users": {
"ada": {
"first": "Ada",
"last": "Lovelace"
},
"alan": {
"first": "Alan",
"last": "Turing"
}
}
}
// Loop through users in order with the forEach() method. The callback
// provided to forEach() will be called synchronously with a DataSnapshot
// for each child:
var query = firebase.database().ref("users").orderByKey();
query.once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
// key will be "ada" the first time and "alan" the second time
var key = childSnapshot.key;
// childData will be the actual contents of the child
var childData = childSnapshot.val();
});
});
Related
I am new to android studio and programming and am currently trying to make my first app. In firebase RTDB, I have multiple push ids under a single child that keep on increasing in number as the user presses certain buttons, and they all store only an integer. I want to retrieve the data from all those push ids(or keys, I don't really know what they are actually called) under the child and then sum the integers up and display the result in a textView and do it every time a new field is added. How can I do that? So far I only know how to normally send and receive data to childs sub-childs like this but i have never ever used push ids or keys before:
String recieve = datasnapshot.child("Child").child("subchild").getText().toString();
String send = "send";
databaseReferenc.child("Child").child("sunchile").setValue(send);
The data tree in firebase is as follows:
Assuming that Australia is a direct child of your Firebase Realtime Database root, to sum all those values, please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference australiaRef = rootRef.child("Australia");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int total = 0;
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String value = Integer.parseInt(ds.getValue(String.class));
total += value;
}
Log.d("TAG", "total: " + total);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
}
};
australiaRef.addListenerForSingleValueEvent(valueEventListener);
One more thing. Because you are storing numbers, it best to store them as long values and not as String values.
so I have a database where I search for products by barcodes.
I wanted to have a check to see if the products are in my database
mFirebaseInstance = FirebaseDatabase.getInstance();
mFirebaseDatabase = mFirebaseInstance.getReference("ProductData");
productId = mFirebaseDatabase.push().getKey();
public void searchProduct(String barcode){
Query barcodeQuery = mFirebaseDatabase.child("Products")
.orderByChild("barcode").equalTo(barcode);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.child("name").getValue(String.class);
int price = ds.child("price").getValue(Integer.class);
int quantity = ds.child("quantity").getValue(Integer.class);
Log.d("DATABASE", name + "/" + price + "/" + quantity); /// The output that I get is this: Neopraxam/25/1 and Vazelina/250/1
That's how I search for the products by barcode.
searchProduct("123123123");
searchProduct("3232");
I have tried to add these methods to check if the value I'm trying to get is null:
if (ds.exists()){} OR
if (ds.getChildrenCount() != 0){}
But I have seen that it doesn't even enter in the loop if the value doesn't exist. So I'm assuming that It's coming from the query.
So, how can I check if the query returns a null value because I used the method .equalTo(barcode) so I suppose that it should return a true or a false value
Issue seem to be with onDataChange signature as it contains NonNull annotation. To execute onDataChange body even for DataSnapshot null value , update the signature as follows
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
.
.
.
}
Note: You should be using SingleValueEventListener instead of ValueEventListener
There is no way in which DataSnapshot's getChildren() method can return null:
Returns
True if the snapshot contains a non-null value, otherwise false
What you should use to solve the issue, is DataSnapshot's exists() method:
Returns
True if the snapshot contains a non-null value, otherwise false
So every time you perform a Query, check each item for existence using the above exists() method.
Besides that, your searchProduct() method can never return a value from the database. For more information, please see my answer from the following posT:
How to return DataSnapshot value as a result of a method?
Im trying to make pagination with Realtime db. I am making query first time with limit 15 and second time based on last item uid i am making second query where suppose to startAt() with that uid. After first query I am receiving as it suppose to 15 items. Next time it suppose to send me back 9 items. But it sends me zero
The code of response
DatabaseReference mReference = realtimeReference.child("OnlineUsers/" + neededGender);
Query query;
if (uid.equals("")){
query = mReference.orderByChild("rating").limitToLast(TOTAL_ITEMS_TO_LOAD);
}else {
//Pagination query with last uid to start
query = mReference.orderByChild("rating").startAt(uid).limitToLast(TOTAL_ITEMS_TO_LOAD);
}
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
final List<OnlineUser> userList = new ArrayList<>();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
OnlineUser user = postSnapshot.getValue(OnlineUser.class);
userList.add(new OnlineUser(user.getUid(), user.getName(), user.getImage(), user.getGender(), user.getCountry(), user.getRating()));
}
EventBus.getDefault().post(new ListEvent(userList));
}
Database structure
When paginating, you always need to pass the value of the property that you order on. In addition, if there are multiple nodes with the same value for that property, you should pass the key of of the first item to return.
So in your case that'd be:
mReference.orderByChild("rating").startAt(rating, key).limitToLast(TOTAL_ITEMS_TO_LOAD);
This assumes that you have the rating of the node in rating and its key in key.
I am seeing an confusing null pointer exception for only ONE of the children of my Firebase Realtime Database reference.
Query query = db.getReference("comments/" + eventId).orderByKey();
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This causes a null pointer exception.
Long date = dataSnapshot.child("date").getValue(Long.class);
// ...
}
// ...
}
I set a break-point and found that evaluating the following expression returns false.
dataSnapshot.child("date").exists();
The debugger displays this value for dataSnapshot:
DataSnapshot { key = c953b8fa-b569-4bc0-9302-3a9b34b22853, value = {0c2fd3e6-e9f1-43ce-a807-06b59e1b00bc={text=this comment is a comment., date=1515593659961, creatorId=gkbZMv2ThMh1xDwKyDP9oUtUIKi2, id=0c2fd3e6-e9f1-43ce-a807-06b59e1b00bc}} }
"date" is clearly present in the snapshot and all of the other children (e.g. "text", "creatorId", "id") are accessible. The only difference is that they are String values and "date" is a long.
How is this possible?
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
This means your code needs to handle the list by looping over DataSnapshot.getChildren():
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
Long date = child.child("date").getValue(Long.class);
// ...
}
// ...
}
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