Accessing the children of a node using a query - java

This is my database structure on firebase Realtime database:
I am trying to access the data under the last uploaded session, which in this case is Session9 and access the sensor readings taken at a specific time.
I have queried the database to give me the last node under data and added a ListenerForSingleValueEvent, at this location i am getting a key in keys List as session9 (only one item) through the following:
Query lastSession = dbref.child("data").limitToLast(1);
lastSession.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot keyNode : dataSnapshot.getChildren()){
keys.add(keyNode.getKey());
Reading reading = node.getValue(Reading.class);
readings.add(reading);
textView.append(reading.getTemperature());
}
}
}
appending the temperature throws this error:
Attempt to invoke interface method 'int java.lang.CharSequence.length()' on a null object reference
readings is an arraylist of Reading class
keys is a list of Strings for storing the keys for example "00:00:06"
I am making some mistake and cannot access the data that i want to add to readings list.
public class Reading {
private String Date;
private String Time;
private String Humidity;
private String Temperature;
private int Sound;
public Reading(){
}

Use this code:
dbref = FirebaseDatabase.getInstance().getReference();
Query lastSession = dbref.child("data").orderByKey().limitToLast(1);
lastSession.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot keyNode : dataSnapshot.getChildren()){
for (DataSnapshot ds : keyNode.getChildren()){
keys.add(ds.getKey());
Reading reading = ds.getValue(Reading.class);
readings.add(reading);
}
}
Here your reference is at node date therefore, you need to add two for loops to be able to access the attributes inside the time.

Upon checking your codes your only getting the key or the seesion but not the chidlrens
Well maybe this can help you creating second query to access the last node children
Query lastSession = dbref.child("data").limitToLast(1);
lastSession.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot keyNode : dataSnapshot.getChildren()){
String lastItem = keyNode.getKey();
//second query
Query secondQuery= dbref.child("data").child(lastItem);
secondQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snap: dataSnapshot.getChildren()){
String temp = snap.child("Temperature").getValue(String.class);
//or you can do this
Reading reads = snap.getValue(Reading.class);
String temp2 = reads.getTemperature();
textView.setText(temp);
}
}
});
}
}
}

The issue stems from that the properties of your Reading class are not publicly accessible to get/set their values.
When you call DataSnapshot.getValue(YourClass.class) or DatabaseReference.setValue(instanceOfYourClass), the class YourClass must have the following:
A public constructor that takes no arguments.
(For getting values) Publicly accessible setters for each property
(For writing values) Publicly accessible getters for each property
The getValue(YourClass.class) function will silently ignore when it fails to set an appropriate property on the target instance of that class.
So to make your Reading class compliant, you would define it using:
public class Reading {
public String Date;
public String Time;
public String Humidity;
public String Temperature;
public int Sound;
public Reading(){
}
}
To fix a potential typo:
Query lastSession = dbref.child("data").limitToLast(1);
lastSession.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot keyNode : dataSnapshot.getChildren()){
keys.add(keyNode.getKey());
Reading reading = keyNode.getValue(Reading.class); // changed node to keyNode
readings.add(reading);
textView.append(reading.getTemperature());
}
}
}
Further reading: Read/Write Data Documentation

Related

Firebase Realtime Database - reading nested data

I am doing a project with firebase, able to save some records on the database, but retrieving it has been an issue for me, I've meddled with other posts from SO but they haven't worked for me. This is how the database looks like (An example):
And my code for retrieving the data:
private void readDataFromDB() {
databaseReference.child("users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user = new User();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
user.setStrName(//Get the Name of the user);
user.setStrScore(//Get the Score of the user));
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
The User class:
public class User {
String strName, strScore;
public String getStrName() {
return strName;
}
public void setStrName(String strName) {
this.strName = strName;
}
public String getStrScore() {
return strScore;
}
public void setStrScore(String strScore) {
this.strScore = strScore;
}
}
How can I get the name and score from each specific user
In your code, you are setting values, you need to be retrieving values using the getters.
Try the following:
databaseReference.child("users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
String name = user.getStrName();
String score = user.getStrScore();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
But, first you need to add the values to the database example:
User user = new User();
user.setStrName("my_name");
user.setStrScore("20");
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("users");
ref.push().setValue(user);
Note setValue():
In addition, you can set instances of your own class into this location, provided they satisfy the following constraints:
The class must have a default constructor that takes no arguments
The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized
You need to add a default constructor to the POJO class public User(){} and also the field names in the class should match the ones in the database. So change this String strName, strScore; into this String name, score; and generate the getters and setters again.
Instead of creating profile in every node you can use a global profile node, and in that store the profile data with their UID, which would make it easier for you to fetch detail of single user.
-profile
-UID1
-name
-score
-UID2
-name
-score
While retrieving you can use getCurrentUser.getUid() to retrieve data for each user:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
databaseReference.child("users").child("profile").child(uid).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User user = new User();
user = dataSnapshot.getValue(User.class);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});

How do you append to an array list in realtime database?

I have a database of users with their emails, role and list of contacts.
I have code to add contacts that when you input into the EditText, it checks through the database if the email exists and if it does, it appends the email into the contacts list. However, nothing gets added in my database.
public void searchContacts(final String emailInput){
final DatabaseReference users;
users = FirebaseDatabase.getInstance().getReference("users");
users.orderByChild("email").equalTo(emailInput).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot userSnapshot: dataSnapshot.getChildren()){
if((userSnapshot.child("email").getValue(String.class).equals(emailInput))){
users.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("contacts").child(emailInput).setValue(true);
}
}
}
Nothing is added, because you haven't create a list yet. To solve this, please use the following code:
public void searchContacts(final String emailInput){
DatabaseReference users = FirebaseDatabase.getInstance().getReference("users");
users.orderByChild("email").equalTo(emailInput).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
List<String> list = new ArrayList<>(); //Create the list
for (DataSnapshot userSnapshot: dataSnapshot.getChildren()){
String email = userSnapshot.child("email").getValue(String.class);
if(email.equals(emailInput)){
users.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("contacts").child(emailInput).setValue(true);
list.add(email); //Add the email the list
}
}
//Do what you need to do with list
}
}
}

Android, Firebase - database only returns single child node as string when trying to retrieve multiple child nodes

I've just started trying to use Firebase in my Android application. I can write data into the database fine but I'm running into a problem when trying to retrieve data.
My database is structured as below
My method for retrieving the data:
public void getCurrentUserData() {
FirebaseDatabase database = FirebaseDatabase.getInstance();
FirebaseUser loggedUser = firebaseAuth.getCurrentUser();
String uid = loggedUser.getUid();
DatabaseReference userRef = database.getReference().child("Users").child(uid);
userRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//crashes because user is not a string
//User user = dataSnapshot.getValue(User.class);
//works because function is returning first child of uID as a string
String user = dataSnapshot.getValue().toString();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
When debugging:
dataSnapshot = "DataSnapshot { key = bio, value = test }"
I was expecting this to return all children contained within uid (bio, dob, firstName, joinDate, lastName, location) and put them into my User object but it actually looks as if its only returning the first child node (bio) as a string.
Why is this happening and how do I retrieve the full set of child nodes?Any help appreciated. Thanks.
If you want to get all properties of the user, you will either need to create a custom Java class to represent that user, or you will need to read the properties from the individual child snapshots in your own code. For example:
userRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String firstName = dataSnapshot.child("firstName").getValue(String.class);
String lastName = dataSnapshot.child("lastName").getValue(String.class);
...
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Alternatively you can loop over the properties with:
userRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot propertySnapshot: dataSnapshot.getChildren()) {
System.out.println(propertySnapshot.getKey()+": "+propertySnapshot.getValue(String.class));
}
}

Retrieve specific child values when know other child value in firebase

I want to retrieve all the doctors' "Firstname" and "Lastname" when I know the "Speciality" of doctor.That's mean when I select specific Specialty area of doctor I want to get all the doctors names which have that Specialty.
To be able to do that try the following:
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference().child("User").child("doctor");
dbRef.orderByChild("Spciality").equalTo("Pathologist").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot datas: dataSnapshot.getChildren()){
String firstName=datas.child("Firstname").getValue().toString();
String lastName=datas.child("Lastname").getValue().toString();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
the snapshot is at child doctor then to retrieve based on the speciality value you need to use the query orderByChild("Spciality").equalTo("Pathologist") to be able to do that. You can change Pathologist as per your requirement.

Firebase data order

I have a class as seen Below:
public class GlobalHighScore {
String name;
int score;
public GlobalHighScore(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
And here I try to make a data receiving.
DatabaseReference scoresRef = firebaseDatabase.getReference("Highscores");
scoresRef.child("GlobalHighScore").orderByChild("score").limitToFirst(10);
scoresRef.addValueEventListener(new ValueEventListener() {
#Override public void onDataChange(DataSnapshot dataSnapshot) {
Iterable<DataSnapshot> keys = dataSnapshot.getChildren();
int i = 0;
for (DataSnapshot key : keys) {
if(i == 10)
break;
orderName[i].setText(key.getValue().toString());
i++;
}
}
When I am doing this, key.getValue().toString() returns json formatted String but I want "name" and "score" seperately. Also, my data is not sorted eventhough I make it sorted.
scoresRef.child("GlobalHighScore").orderByChild("score").limitToFirst(10);
I think I having problem here.
Edit: When I order by "score", it gives data according to date.
Last form is
final TextView[] orderScore = {firstscore, secondscore, thirdscore, fourthscore, fifthscore, sixthscore, seventhscore, eightscore, ninthscore, tenthscore};
final TextView[] orderName = {firstname, secondname, thirdname, fourthname, fifthname, sixthname, seventhname, eightname, ninthname, tenthname};
DatabaseReference scoresRef = firebaseDatabase.getReference("Highscores").child("GlobalHighScore");
scoresRef.orderByChild("score").limitToFirst(10);
scoresRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int i = 0;
for (DataSnapshot data : dataSnapshot.getChildren()) {
if(i == 10)
break;
String name = data.child("name").getValue().toString();
String score = data.child("score").getValue().toString();
orderName[i].setText(name);
orderScore[i].setText(score);
i++;
}
}
It gives no data record at all.
Try this:
DatabaseReference scoresRef = firebaseDatabase.getReference("Highscores").child("GlobalHighScore");
Query q=scoresRef.orderByChild("score").limitToFirst(10);
q.addValueEventListener(new ValueEventListener() {
#Override public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot data : dataSnapshot.getChildren()){
String name=datas.child("name").getValue().toString();
String score=datas.child("score").getValue().toString();
}
}
Since you want the name and the score alone you can do the above, to be able to retrieve them alone.
.orderByChild("score").limitToFirst(10);, using this you will get the first 10, nodes that have the child score.
limitToFirst(10) //to get the first 10 of a specific child
limitToLast(10) //to get the Last 10 of a specific child
When you are using the following line of code:
Iterable<DataSnapshot> keys = dataSnapshot.getChildren();
The childrens that you are getting when iterating are actual objects, not Strings. Using toString() method doesn't make any sense because you cannot cast an Object to a String and expect to get the values within it. That's why you are getting that "json formatted Strings". So what are you getting when iterating are actual maps. So to get the name and score you need to iterate through the map and use: map.get("name"); and map.get("score");.
You don't need to change the entire code, your code is fine. Just solve this minor issue.

Categories