Child value = null - android

I have a database that looks like this:
database
|
places
|
user1
| |___indoors: "yes"
| |___outdoors: "yes"
|
user2
|___indoors: "yes"
|___outdoors: "no"
When I do the following, I get all users places information as a single object (converted to String) with no problems:
ValueEventListener placesListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String locations = dataSnapshot.toString(); // I get the entire tree as String
}
}
//this is how I set the listener to changes
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference reference = database.child("places");
reference.addValueEventListener(placesListener);
But, when I want only the indoors children, I get DataSnapshot {key = indoors, value = null}.
This is how I try to get only the indoors keys and values (almost the same, only adding extra .child("indoors"):
ValueEventListener placesListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String indoors = dataSnapshot.child("indoors").toString(); // I get value = null
}
}
// listener remains the same

The data contained in a DataSnapshot is relative, like a JSON tree. From the documentation on DataSnapshot#child():
Get a DataSnapshot for the location at the specified relative path. The relative path can either be a simple child key (e.g. 'fred') or a deeper slash-separated path (e.g. 'fred/name/first'). If the child location has no data, an empty DataSnapshot is returned.
In your example, there is no child named indoors directly under the places node. Instead, you have 2 children named user1 and user2 which each have a child named indoors. Therefore, in order to access one of the indoors children, you'll need to do something like:
dataSnapshot.child("user1").child("indoors").toString();
Alternatively, you can iterate through the children using:
for (DataSnapshot childSnapshot : dataSnapshot.getChildren()) {
Log.d(childSnapshot.getKey() + ": indoors=" + childSnapshot.child("indoors").toString());
}

Related

Retrieve data from multiple push ids under a single child in firebase realtime database

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.

Firebase Database check if it's null value, doesn't work with DataSnapshot

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?

Returning zero nodes in realtime startAt query

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.

OrderByChild() is not sorting my firebase data

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();
});
});

Firebase null pointer exception referencing child

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);
// ...
}
// ...
}

Categories

Resources