Firebase Database. Retrieve nested data - android

MY CURRENT CODES (now its working)
#Override
protected void onStart() {
super.onStart();
petshopRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
petshopsList.clear();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Petshops petshops = postSnapshot.getValue(Petshops.class);
petshopsList.add(petshops);
}
CustomerPetshopAdapter adapter = new CustomerPetshopAdapter(CustomerViewPetshopActivity.this, R.layout.customlist_viewpetshop, petshopsList);
lvPetshops.setAdapter(adapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
QUESTION:
Lets say i have
petshopRef = FirebaseDatabase.getInstance().getReference("Petshops");
How do I retrieve all data in Blue Circle (in my image above)

You can retrieve all the data using the once value event. Then you can loop through it to get each key and value. I'm writing this logic in nodejs, you can convert it into your java logic.
Example,
petshopRef.once('value', function(snap){
snap.forEach(listData=>{ //list data will have top level auto generated keys
listData.forEach(element=>{
element.key // will be the key, in your case (brcat)
element.val() // will be the corresponding value to above key. in your case (3)
});
});
});

Related

Firebase startAt returns null when retrieving data

I am trying to retrieve a list that is on a child that starts with something. Below is a sample of data in my Firebase realtime database:
In the image, I want to retrieve all data that starts with the keyword "jsonmat".
I am using thee code below but it always return null:
DatabaseReference db = FirebaseDatabase.getInstance().getReference()
.child("Events");
db.startAt("jsonmat").addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i("events", dataSnapshot.toString());
for (DataSnapshot data : dataSnapshot.getChildren()) {
// here the user will have the specified email only
}
}
#Override
public void onCancelled(DatabaseError databaseError){
Log.i("MyApp", "getUser:onCancelled", databaseError.toException());
}
});
What you're trying to do isn't possible. You can't order/filter of a nested key, only on direct child keys (-M...) and on nested values (active: true).
Typically you'll want to create a new top-level node, where you store the keys you're searching for, and then the push keys for each matching nested node:
"category_things": {
"jsonmat_jsonmat": {
"-M62....uYgB": true,
"-M62....2-eO": true
}
}
Also see:
Firebase Query Double Nested
My original, but wrong answer is below...
If you use startAt without specifying an orderBy... clause, the data will be ordered by priority. This priority is a left-over from before Firebase supported ordering on specific properties, so mostly it means that you must call an orderBy... method before filtering.
So:
DatabaseReference db = FirebaseDatabase.getInstance().getReference().child("Events");
db.orderByKey().startAt("jsonmat").addListenerForSingleValueEvent(new ValueEventListener() {
...
What you can do for your case, is to loop 2 times over the children of the node Events:
//the reference to the node Events
DatabaseReference db = FirebaseDatabase.getInstance().getReference().child("Events");
db.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//loop 1
for (DataSnapshot data : dataSnapshot.getChildren()) {
//loop2
for (DataSnapshot dataTwo : data.getChildren()) {
//get the key
String key = dataTwo.getKey();
if(key.startsWith("jsonmat")){
//we got a matching key so extract the data and maybe put them in a list
boolean active = dataTwo.child("active").getValue(Boolean.class);
int bet = dataTwo.child("bet").getValue(Integer.class);
String challenger = dataTwo.child("challenger").getValue(String.class);
String competitor = dataTwo.child("competitor").getValue(String.class);
String game = dataTwo.child("game").getValue(String.class);
............
............
............
}else{
//we didn't get a match
}
}//end loop2
}//end loop1
}
#Override
public void onCancelled(DatabaseError databaseError){
Log.i("MyApp", "getUser:onCancelled", databaseError.toException());
}
});

How to modify an specific value in Firebase?

I have this data in Firebase Database:
Negocios:
-KjfCu56lFZCybYldBZy
lugarReference: "Restaurante"
numeroMesas:39
password:"pass123"
user:"user123"
user_id:"usr_1"
I have two applications connected to one project in Firebase, one of them upload data of restaurants reservation, and the other one displays reservations in a RecyclerView.
In the first application, once I do a reservation, it must minus one to numeroMesas value, the other application should display any changes to this key.
In the reservation application, I have this piece of code that I did base in this question:
Update specific keys using Firebase for Android
It supposes to modify the value of numeroMesas, but it does not:
mReference.child("Negocios").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot postSnapshot : dataSnapshot.getChildren()){
Lugar lugar = postSnapshot.getValue(Lugar.class);
if(nombre_lugar.equals(lugar.getUser_id())){
DatabaseReference numMesasReference = mReference.child(dataSnapshot.getKey()).child("numeroMesas");
numMesasReference.setValue(lugar.getNumeroMesas() - 1);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
What it does is the next thing:
Negocios:
-KjfCu56lFZCybYldBZy
lugarReference: "Restaurante"
numeroMesas:39
password:"pass123"
user:"user123"
user_id:"usr_1"
-Negocios
-KjfCu56lFZCybYldBZy
numeroMesas:39
How can be fixed?
I need to minus one once I do a reservation...
Greetings!
Using postSnapshot.getRef() you obtain a reference to the source location for this snapshot. So what's next is to add a child to that reference, that reference will be "numeroMesas" that is the key you want to modify.
As easy as that, the code will be like this.
mReference.child("Negocios").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot postSnapshot : dataSnapshot.getChildren()){
Lugar lugar = postSnapshot.getValue(Lugar.class);
if(nombre_lugar.equals(lugar.getUser_id())){
DatabaseReference numMesasReference = postSnapshot.getRef().child("numeroMesas");
numMesasReference.setValue(lugar.getNumeroMesas() - 1);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
P.S: If you want to minus one just once by reservation, addValueEventListener() won't work, it will minus multiple time as a loop. Use addListenerForSingleValueEvent() instead addValueEventListener().
As the name says, this listener fits for single changes in the data at any location.
I guess the problem is with dataSnapshot.getKey() in this line
DatabaseReference numMesasReference = mReference.child(dataSnapshot.getKey()).child("numeroMesas");
Here you getting the key for the whole list of Negocios, not for the specific child replace it with `
postSnapshot.getKey()
The problem is that your DatabaseReference that you are using is wrong. You are missing a child. So in order to solve this problem, please use the following code:
mReference.child("Negocios").child(negociosId).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int numeroMesas = (int) dataSnapshot.child("numeroMesas").getValue();
if(nombre_lugar.equals(lugar.getUser_id())){
mReference.child("Negocios").child(negociosId).child("numeroMesas").setValue(numeroMesas - 1);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
In which negociosId is the unique id generated by the push() method.
Hope it helps.
I'm new to firebase and android. But If the above solutions doesn't work please do the following. I think the problem is that you didn't convert the value of numeroMesas to string. Sorry if there's anything wrong.
Hope it helps.
mReference.child("Negocios").child(negociosId).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(nombre_lugar.equals(lugar.getUser_id())){
mReference.child("Negocios").child(negociosId).child("numeroMesas").setValue((Integer.parseInt(dataSnapshot.child("numeroMesas").getValue().toString())) - 1);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});

ArrayList gets empty after first snapshot

I'm working with firebase in a android application and something strange ocurred, in my example I need two snapshots, 1 to get the users inside a list ( I use this snapshot to fill a arraylist of strings with the key of the user) and the other to compare to the users, the strange behavior is that my arraylist is empty after the first snapshot, I used logcat to check it and that Log inside the firstsnapshot returns me 1 as the size of the arraylist, the second returns me 0, dunno how it gets 0 again.
Here is my code:
private void prepareFriendList() {
myRef.child(id).child("FriendLists").child(group).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String keyUser;
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Log.d("number:",snapshot.getKey());
keyUser = snapshot.getKey();
currentFriends.add(keyUser);
Log.d("hello",String.valueOf(currentFriends.size()));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
for(String s: currentFriends){
Log.d("idddd",s);
}
Log.d("hello",String.valueOf(currentFriends.size()));
myRef.child(id).child("Users").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
User user = snapshot.getValue(User.class);
for(String item: currentFriends){
if (snapshot.getKey().equals(item)) {
usersList.add(user);
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mAdapter.notifyDataSetChanged();
}
I don't understand why that happens, since I'm adding the key inside the arraylist, any tip?
This is happening because onDataChange is called asynchronously. This means that the statement that adds users to the list is executed before onDataChange has been called. That's why your list is empty outside that method. So in order to use that lists, you need to use it inside the onDataChange() method.
For other approach, please visit this post and this post.
Hope it helps.

Dealing with Asynchronous Listeners in Firebase to Retrieve Data

I am learning to use Firebase and want to know if I am doing it right. If I understood correctly, you can only retrieve data asynchronously using a listener in Firebase. I will try to explain my question with an example. Say I have the following database data for a simple chat application:
chat_info:
chatID_1:
participants:
uId_1: true
uId_2: true
users:
uId_1:
display_name: "David"
participated_chats:
chatID_1: true
chatID_2: true
uId_2:
display_name: "Jason"
participated_chats:
chatID_1: true
chatID_2: true
Now, I am trying to list the chats that David is participated in. So I do something like the following:
ArrayList<String> chatIdList = new ArrayList<String>();
// Retrieve chat Ids of participating chats
usersRef.child(mFirebaseUser.getUid()).child("participated_chats").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
chatIdList.clear();
// Save each chat Id to an arraylist
for (DataSnapshot child : dataSnapshot.getChildren()) {
chatIdList.add(child.getKey());
// when loop hits the last user of the dataSnapsot
if(chatIdList.size() >= dataSnapshot.getChildrenCount()) {
// For each chat Id, retrieve participants' uIds
for(String chatId : chatIdList) {
chatInfoRef.child(chatId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Chat chat = dataSnapshot.getValue(Chat.class); // In a Chat class, there is public Map<String, Boolean> participants = new HashMap<>();
chatDetailList.add(chat);
chatListAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Now, I have participants' uIds for each chat that a user is participated in. But, since I want to display the username, not the uId, I have to retrieve data from another node again. Here is my worry because I have to add another asynchronous listner to retrieve data from different node. If it was something like MySQL, it would not be a problem, but Firebase listener is asynchronous. This idea of asynchronous listener to retrieve data is very confusing and wonders if I am doing it right. What should I do here?
You can just attach the first listener to the /users/uId_1 to get the whole user object, and then you can simply get the user's username / display name from the dataSnapshot value.
Here's an example.
ArrayList<String> chatIdList = new ArrayList<String>();
// Retrieve chat Ids of participating chats
usersRef.child(mFirebaseUser.getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
chatIdList.clear();
User user = dataSnapshot.getValue(User.class);
String username = user.getDisplay_name();
Map<String, Boolean> participated_chats = user.getParticipated_chats();
// Save each chat Id to an arraylist
for (Map.Entry<String, Boolean> child : participated_chats.entries()) {
chatIdList.add(child.getKey());
// ... continues
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

How to retrieve all objects from a Node in Firebase database?

I followed the documentation, but no matter what, I cannot figure out how to return all the objects from a single node. For example, I want to return a list of all company objects from the companies node. Once I have that list, I want to parse them all into JSON objects. This is my first time with a NoSQL database so I'm sure that I'm missing something small.
Currently I have:
DatabaseReference companiesRef = FirebaseDatabase.getInstance().getReference("12265");
companiesRef.child("companies").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("Count ", dataSnapshot.getChildren().toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
But it just returns null for the value: DataSnapshot { key = companies, value = null }.
Here's my database:
You create your reference like this:
FirebaseDatabase.getInstance().getReference("12265");
This means that Firebase looks at the root of the database and returns the child 12265 from under there. It does not automatically search the tree for a node with a matching name.
So you'll need to specify the entire path:
FirebaseDatabase.getInstance().getReference("android/users/12265");
Don't add any parameters to your getReference() (let it go to the root of database) and then set the addListenerForSingleValueEvent. And you have not used getvalue() on you datasnapshot as well. Try this code:
DatabaseReference companiesRef = FirebaseDatabase.getInstance().getReference();
// this is the patch that I see from the image that you have attached.
companiesRef.child("telenotes").child("android").child("user").child("12265").child("companies").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("Count ", dataSnapshot.getChildren().getValue().toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

Categories

Resources