Get Firebase data from certain child - android

I'm starting to code Android Apps with the database connection. As IDE I use Android Studio and Firebase for the database. This is my data structure in Firebase:
In my app, I need to fill a ListView with all the names. So I want the data from three children from the child "Rezepte" from the UUID child. I hope this is understandable.
I've done a lot of googling and I just can't figure out how this works. My current version of the java code is this:
final FirebaseUser user = firebaseAuth.getCurrentUser();
// trying to get the reference of the right path
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child(user.getUid()).child("Rezepte");
ref.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// calling a method which should read the data from the snapshot and put it into the ListView
fillList((Map<String, Object>) dataSnapshot.child(user.getUid()).child("Rezepte").getValue());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(RezepteActivity.this, "Daten konnten nicht gelesen werden", Toast.LENGTH_SHORT).show();
}
});
}
private void fillList(Map<String, Object> entries) {
// loop to cycle through every child of "Rezepte" and get the names
for (Map.Entry<String, Object> entry : entries.entrySet()) {
Map singleEntry = (Map) entry.getValue();
// add the name to an ArrayList of all names
Rezepte.add((String) singleEntry.get("name"));
}
// put the data into the ListView
lvRezepte.addFooterView(lvRezepte, Rezepte, true);
}
The app always crashes and I don't really understand a lot in the debugger. But the error occurs already in the onDataChange void.
I would be really happy if someone could help me.

You're trying to traverse down the hierarchy in your result DataSnapshot when you've already done so in your query itself. So in your onDataChange() you need to just put:
fillList(datasnapshot.getValue()) //Map of results at /{uid}/Rezepte

Assuming that fillList method works properly, you should first fix the following line
fillList((Map<String, Object>) dataSnapshot.child(user.getUid()).child("Rezepte").getValue())
to
fillList((Map<String, Object>) dataSnapshot.getValue())
You already have a reference to Rezepte child of the current user when you declared it like this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child(user.getUid()).child("Rezepte")
Your snapshot has 1, 2, and 3 as children, so you shouldn't reinforce the path you declared in the reference.

To get all those names and add them to an ArrayList, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference rezepeteRef = rootRef.child(user.getUid()).child("Rezepte");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<String> list = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.child("name").getValue(String.class);
list.add(name);
Log.d("TAG", name);
}
Log.d("TAG", list);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
rezepeteRef.addListenerForSingleValueEvent(eventListener);

Related

What is the best way to add data to a list in Firebase Realtime Database

I'm using firebase realtime db, and I'm storing a list of string in a particular storage reference. Currently, to add something to the list
I'm doing the following steps.
Read the database childreference
get the datasnapshot and check if it is null (which means first
time)
if it is null, directly set your local list
if dataSnapshot.getValue(); not null then (already data present in
the db, so need to append the new data to th e end of it.)
save the remote list from dataSnapshot.getValue(); to a local variable.
then add the new data to the end of it
now the local list contains all the items in remote as well as new
items. save this to the child reference
Below is the code I have written for that
DatabaseReference reference = root()
.child(userId)
.child(list_id);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
reference.removeEventListener(this);
List<String> value = new ArrayList<>();
if (dataSnapshot.getValue() == null) {
value.add(message);
} else {
if (dataSnapshot.getValue() instanceof List && ((List) dataSnapshot.getValue()).size() > 0 && ((List) dataSnapshot.getValue()).get(0) instanceof String) {
value = (List<String>) dataSnapshot.getValue();
value.add(message);
}
}
reference.setValue(value, (databaseError, databaseReference) -> {
finish();
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
finish();
}
private void finish() {
Log.e(TAG,"save finished");
}
});
Thats a lot of steps to do a simple operation. Also , all the time I'm pulling the whole data from remote and appending the new data to it.
is there any easy way to do this? I tried with the 'push()' method as follows
DatabaseReference reference = root()
.child(userId)
.child(list_id).push();
But it adds a new key always to the value I add. Can anyone explain what is the proper way to do it with less code?
UPDATE:
My db structure is as shown below
The solution you gave it's very good but why to remove the listener inside the callback?
I'll write you the code to be more simpler. Please see it below:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference listIdRef = rootRef.child("list").child(list_id);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<String> list = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String comment = ds.getValue(String.class);
list.add(comment);
}
//Do what you need to do with your list
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage());
}
};
listIdRef.addListenerForSingleValueEvent(valueEventListener);
Don't ignore errors.
The simplest way in which you can add a new child in your 08-10-18 node, without the need to get the enitire list, would be using only the following lines of code:
Map<String, Object> map = new HashMap<>();
map.put("5", "comment55");
rootRef.child("list").child(list_id).updateChildren(map);
But even a better solution would be to use instead of lists, maps and the children should be added using the push() method. So your database structure should look like this:
Fireabase-root
|
--- usr100
|
--- 08-10-18
|
--- randomId: "comment1"
|
--- randomId: "comment2"
|
--- randomId: "comment3"
|
--- randomId: "comment4"
And the code should look like this:
String key = rootRef.child("list").child(list_id).push().getKey();
Map<String, Object> map = new HashMap<>();
map.put(key, "comment5");
rootRef.child("list").child(list_id).updateChildren(map);
In this case you don't have to worry about the key, which is not a number anymore. Without the help of the push() method, you need to get the entire list, as explained in the first part of my answer, add the new element and the update the list in the database.
This is just an update to the existing accepted answer, which I tried and working. This is the same process with less lines of code, without using the ValueEventListener and making use of the updateChildren method as mentioned in the accepted answer.
DatabaseReference reference = deviceRootReference().child(userId).child(list_id).push();
Map<String, Object> map = new HashMap<>();
map.put(reference.getKey(), comment);
Tasks.await(reference.updateChildren(map));
NOTE: This code performs the db write synchronously (Tasks.await blocks the thread), so the above piece of code should run in a background thread only

How can i retrieve a specific data from nodes in firebase and display to lisltview

I already have knowledge in retrieving data from firebase. The thing is, the data i want to retrieve lies under 3 parent nodes, and I can't figure any way how to retrieve data from the database 3 nodes deep. What I want is to get all the values of the key named "name" and display it in a listview.
To display all those names, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference medicinesRef = rootRef.child("Medicines");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.child("name").getValue(String.class);
Log.d("TAG", name);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
medicinesRef.addListenerForSingleValueEvent(eventListener);
Your output will be:
amoxcillin
paracetamol
mefenamic

Searching firebase if a value exists or not

I have the following data structure in my firebase. I am implementing a coupon based system where you enter a code in dialogue box and it is searched across the database. So I have been trying to figure out this but I haven't found the perfect query that can search the code, if found, then get all the other child values too.
Below is the code that i have been trying with:
private void couponsearch() {
final EditText taskEditText = new EditText(this);
AlertDialog.Builder dialog = new AlertDialog.Builder(this)
.setTitle("Akiba Yangu")
.setMessage("Enter Akiba Code Here.")
.setIcon(R.drawable.akyi)
.setView(taskEditText).setPositiveButton("SAVE",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
String stringe = taskEditText.getText().toString();
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child("codes").orderByChild("code").equalTo(stringe).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Coupons coo = dataSnapshot.getValue(Coupons.class);
String name = dataSnapshot.getKey();
int codez = coo.getValuee();
code.setText(name);
if(dataSnapshot != null && dataSnapshot.getChildren().iterator().hasNext()){
for(DataSnapshot ds : dataSnapshot.getChildren()) {
codegotten();
}
}else {
nocode();
}
int val = coo.getValuee();
Akibasavings as = new Akibasavings();
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
System.out.println(val);
code.setText(name);
as.setName(name);
as.setAmount(val);
final Firebase ref = new Firebase("https://akiba-c9600.firebaseio.com/");
Firebase newRef = ref.child("Savings"+uid).push();
newRef.setValue(as);
sendNotification();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
public void onCancelled(FirebaseError firebaseError) {
//Username Does Not Exist
}
});
}
});
dialog.show();
}
I would like to search the code, check if it is really there or not: if it is there I need to get all the other values too, i.e there are three nodes in every child. code, brand, value. After I have checked that the code exists, I would like to also get the other values associated with it. Regards
To achieve this, i recomand you change the structure of your database a little bit by adding a new node named coupons. Your database should look like this:
Firebase-root
--- coupons
TTUUPP: true
KKLLOO: true
To check if a coupon exists in your database, just add a listener on the new created node and use exists() method. This is a coomon practice within Firebase named denormalization and is for simplify and reduce query and bandwith. This what you need.
What you need is Query.
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
Query mQuery = mDatabase.child("codes").orderByChild("code").equalTo(stringe);
mQuery.addListenerForSingleValueEvent(new ValueEventListener() {
// use single value event listener to detach listener immediately after query
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
// code exists, cast your data to relevant object
// note that if multiple entries exists, you need to loop through them
} else {
// code does not exists
}
}
});
Read the official document here.
Note that you must remember to index your firebase properly! Query on firebase is not the same as local database query. If you do not index your firebase, the query will download everything under the codes section into user phone, before doing the search locally on user phone. This will consume high bandwidth and memory. Learn more about index here. Read about my personal issue with index previously here.
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.
Your onDataChange() needs to handle the fact that the snapshot contains a list of result by looping over DataSnapshot.getChildren():
mDatabase.child("codes").orderByChild("code").equalTo(stringe).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
Coupons coo = childSnapshot.getValue(Coupons.class);
String name = childSnapshot.getKey();
int codez = coo.getValuee();
code.setText(name);
...
}
}

Firebase user details are not retrieved in Android

I am storing user details 'firstname' and 'lastname' in UserNode. But when i want to retrieve that details then no data is being retrieved. I tried almost all solutions on the internet but nothing solved my problem. Here is my code for retrieving data of the current user:
FirebaseUser userr = FirebaseAuth.getInstance().getCurrentUser();
if (userr != null) {
String name = userr.getDisplayName();
Log.e("value", name);
}
but it says "println needs a message"
I also tried with this but nothing happened:
DatabaseReference DataRef;
DataRef = FirebaseDatabase.getInstance().getReference().child("UserNode");
DataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String acctname = (String)dataSnapshot.child("firstname").getValue();
Log.e("name", acctname);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
]1
Please help me I am stuck with it
You're reading a collection of user with a ValueEventListener. As the [Firebase documentation for reading lists with a value event](Listen for value events) explains:
While using a ChildEventListener is the recommended way to read lists of data, there are situations where attaching a ValueEventListener to a list reference is useful.
Attaching a ValueEventListener to a list of data will return the entire list of data as a single DataSnapshot, which you can then loop over to access individual children.
Even when there is only a single [child node], the snapshot is still a list; it just contains a single item. To access the item, you need to loop over the result.
So in your code:
DatabaseReference DataRef;
DataRef = FirebaseDatabase.getInstance().getReference().child("UserNode");
DataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String acctname = (String)childSnapshot.child("firstname").getValue();
Log.i("name", acctname);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Using FirebaseUser:
FirebaseUser implements UserInfo and in UserInfo's getDisplayName() documentation says
Returns the user's display name, if available.
So, it is possible that FirebaseUser.getDisplayName() return null when display name is not set. In that case Log.e() receives null as message and therefore prints println needs a message
Using your own structure:
Instead of using type conversion use getValue(Class<T>) like so:
String acctname = dataSnapshot.child("firstname").getValue(String.class);
Please, read how to retrieve data from firebase. I think you have a problem because you don't have Class Model.
Your steps:
Create model UserModel with firstname and lastname field
Use listener (example from docs):
// Attach a listener to read the data at our posts reference
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Post post = dataSnapshot.getValue(Post.class);
System.out.println(post);
}
#Override
public void onCancelled(DatabaseError databaseError) {
System.out.println("The read failed: " + databaseError.getCode());
}
});
See other answers: How to retrieve data from one single userID Firebase Android and retrieving data from firebase android

Get element by key with Firebase

I've been trying to retrieve an element from my Firebase database using its key. I have a class User and users are present in database.
I want to retrieve an object user using its key with this method :
public User getConnectedUserByUId(final String uid){
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("users");
final List<User> connectedUser= new ArrayList<User>();
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot item: dataSnapshot.getChildren()) {
if (item.getKey()==uid)
{
User user= dataSnapshot.getValue(User.class);
connectedUser.add(user);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return connectedUser.get(0);
}
but it returns an empty list every time.
The issue is here:
if (item.getKey()==uid)
since you are comparing 2 String in java you have to use the method
string.equals(Object other) not the == operator.
Moreover, since you know the key of the data in Firebase you can use it to get the reference without cycling all children.
Something like:
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("users").child(uid);
Here you try to check a very specific ID only on changed data. Instead, try using a Firebase Query with filterByKey and not using your own function to achieve that. Here's sample code that I would use to try to replace your function:
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("users");
Query connectedUser = ref.equalTo(uid);
connectedUser.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
// TODO: handle the post here
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
});
As specified in the Firebase documentation here: https://firebase.google.com/docs/database/android/lists-of-data#filtering_data
in the line : User user= dataSnapshot.getValue(User.class);
you have to put : User user= item.getValue(User.class);
and you have to check the id after you get the user:
if (user.getKey()==uid){
connectedUser.add(user);
}
There are 2 mistakes and a minor issue:
you are using == to compare two String objects. In java, this is true only if they are the same reference. Use equals instead.
addValueEventListener only adds a listener that gets invoked once after you add it and then every time something changes in the value you are listening to: this is an asynchronous behaviour. You are trying to get data synchronously instead. Please read something about this.
you are fetching useless data: you only need an object but you are fetching tons of them. Please consider to use the closest reference you can to the data you are fetching.
So, in conclusion, here's some code. I'd like to point out right now that forcing synchronous acquisition of naturaly asynchronous data is a bad practice. Nevertheless, here's a solution:
public User getConnectedUserByUId(final String uid){
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("users").child(uid);
Semaphore sem = new Semaphore(0);
User[] array = new User[1];
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot item: dataSnapshot.getChildren()) {
if (item.getKey()==uid)
{
User user= dataSnapshot.getValue(User.class);
array[0] = user;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
try
{
sem.tryAcquire(10, TimeUnit.SECONDS);
}
catch (Exception ignored)
{
}
return array[0];
}
EDIT: I've just seen that this post is very old. I'm not sure how I ended up here.

Categories

Resources