How do I retrieve all the children under a node in Firebase? - android

How do i retrieve all the information stored under the Post node. I would like to add the value to my post list which in turn will populate my recycle view. I have already tried accessing my database with the users UID but that only retrieves information for a single user.
My firebase structure
Post
fyvqJOIym3RMNS7L29Oqij9HUX12 (UID)
-LlCmqQCSmdfK9lhCjuP (Random push key)
desc:
id:
image:
name:
profileimage:
-LlCn0eTBh3dHRGek95j (Random push key)
desc:
id:
image:
name:
profileimage:
/Retrieves information stored inside Post node...
public void fetchUserInfo() {
Toast.makeText(this, "fetch info method called", Toast.LENGTH_SHORT).show();
postRef = FirebaseDatabase.getInstance().getReference().child("Post");
postRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
value = ds.getValue(Post.class);
postList.add(value);
randomPostKeyId = ds.getKey();
}
adapter = new Adapter(Shop_Activity.this, postList);
recyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.i("Error", databaseError.toString());
}
});
}

So you have
--Post
----userUID1
------postUUID
--------postData
------postUUID
--------postData
----userUID2
------postUUID
--------postData
May I suggest you to structure the data this way:
-- Posts
---- postUUID 1
------ author: userUUID 1
------ desc: ...
------ image: ...
------ name: ...
---- postUUID 2
------ author: userUUID 1
------ desc: ...
------ image: ...
------ name: ...
---- postUUID 3
------ author: userUUID 2
------ desc: ...
------ image: ...
------ name: ...
////////////////////////////
-- Users
---- userUUID 1
------ profileimage: ...
------ ......
---- userUUID 2
------ profileimage: ...
------ ......
And when you want to query posts by user just query this way: ref.child("Posts").orderByChild("author").equalsTo(userUID).add...
and if you want all the posts just query this way:
ref.child("Posts").addChildEventListener(new ChildEventListener(){*/methods implementatio/*})
and in onChildAdded(){...} you get only single post data but this will retrieve all posts one by one and continue listening for new ones in realtime, so you just get this single post and pass it as param in a method to display this data in a desired View. Also if you want to display the user info you just query the user inside (you can create a hashmap with (String, UserClass) like (userUID, UserData) and check if you have the data for this user already and if you have it just get it instead of downloading it again and again).
But if you want to stick with this, check this out:
public void fetchUserInfo() {
Toast.makeText(this, "fetch info method called", Toast.LENGTH_SHORT).show();
postRef = FirebaseDatabase.getInstance().getReference().child("Post");
postRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
for(DataSnapshot singlePostData : ds.getChildren() {
value = singlePostData.getValue(Post.class);
postList.add(value);
randomPostKeyId = singlePostData.getKey();
}
}
adapter = new Adapter(Shop_Activity.this, postList);
recyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.i("Error", databaseError.toString());
}
});
}
Since you obtain all the childs in Post you get objects with key userID and list with posts as value. you must iterate over each object with userID and list of posts and inside each loop to iterate over this list of posts. The code may not be very accurate but this is the logic.

Related

How to retrieve data in sorted manner

I want to fetch data from firebase real time database in Ascending order.
BirthdayPersons //This is main node
-Lfk hfkfks //This is sun node
dob: "01/10/2019"
name: "Random Name"
uid: "randomstring"
rem: 5 //Sort according to this
-Lafkjhf fksjfj
dob: "01/10/2019"
name: "Random Name"
uid: "randomstring"
rem: 5
I have Json tree of this format and I want the data in ascending order according to remaining
This is my database model class
data class Databasemodel(val uid:String, val name:String, val dob:String,val rem:Int) {
constructor():this("",",","",0)
}
Try using:
FirebaseDatabase.getInstsnce().getReference("BirthdayPersons").orderByChild("rem")
.addValueEventListener(new ValueEventListener() {
#Override public void onDataChange(DataSnapshot dataSnapshot) {
// implement logic here
}
#Override public void onCancelled(DatabaseError error) {
// Failed to read value Log.w(TAG, "Failed to read value.", error.toException());
}
});

Firebase Child Listener Callback Returns one value and null for second value

I'm facing very strange results when working firebase realtime database for Android.
The main problem is:
When I try to add a child with two fields, the onChildAdded method returns the inserted value for first key and null for second and is not called for second value of the newly inserted child.
When I try to do the same thing with valueEventListener, the onDataChange method is called twice whenever a new child is created. In the first callback, the value of one field in returned and second value is null and in second callback both updated values are returned.
I have this structure in my firebase database.
{
"users" : {
"-LOOlXqtc0XK3ZXLKFc6" : {
"Age" : 50,
"Name" : "Ali"
},
"-LOPIfgGQMhyMkRMcpTb" : {
"Age" : 80,
"Name" : "New Name"
}
}
}
And this is my MainActivity code:
mDatabase = FirebaseDatabase.getInstance();
mRef = mDatabase.getReference("users");
This code is executed on Insert Data button's on click.
private void runCode(View view){
String name = mInputText.getText().toString();
int age= Integer.parseInt(mInputNum.getText().toString());
String key = mRef.push().getKey();
mRef.child(key).child("Name").setValue(name);
mRef.child(key).child("Age").setValue(age);
}
And this is read data button's on click method using valueEventListener.
private void readData(View view) {
//read data here
//this read data method has value listener not child listener
mRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Person data= dataSnapshot.getValue(Person.class);
Map<String,Object> data1= (Map<String, Object>) dataSnapshot.getValue();
Log.d(TAG, "onChildAdded: Name: "+data1.get("Name"));
Log.d(TAG, "onChildAdded: Age: "+data1.get("Age"));
Log.d(TAG, "This is Person: "+data);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
The logcat output is this:
This is when I click on Read data method for the first time.
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}
And this is logcat output when I insert a new child with Name="New Name" and age=80.
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: null
D/MyTag: This is Person: Person{Name='New Name', Age=0}
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: This is Person: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: 80
D/MyTag: This is Person: Person{Name='New Name', Age=80}
The callback method is separately for each field, it returns one field at a time, but this make sense that the setField is called twice so may be thats why it is called. But with child listener, the case is even worse.
Here is Read Code method with childListener implementation.
private void readData(View view) {
//read data here
mRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Map<String,Object> data= (Map<String, Object>) dataSnapshot.getValue();
Person p=dataSnapshot.getValue(Person.class);
Log.d(TAG, "onChildAdded: Name: "+data.get("Name"));
Log.d(TAG, "onChildAdded: Age: "+data.get("Age"));
Log.d(TAG, "onChildAdded: Person is: "+p);
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Here is the logcat output when I click read data button for first time:
D/MyTag: onChildAdded: Name: Ali
D/MyTag: onChildAdded: Age: 50
D/MyTag: onChildAdded: Person is: Person{Name='Ali', Age=50}
D/MyTag: onChildAdded: Name: New Name
D/MyTag: onChildAdded: Age: 80
D/MyTag: onChildAdded: Person is: Person{Name='New Name', Age=80}
And this is the output with adding a new child with Name="Usman" and age=50
D/MyTag: onChildAdded: Name: Usman
D/MyTag: onChildAdded: Age: null
D/MyTag: onChildAdded: Person is: Person{Name='Usman', Age=0}
Only this happens in callback. The age is not returned but value is stored in Database correctly.
Please help. I have only one listener attached and always run the app after stopping running process.
Thanks.
When you run this code:
mRef.child(key).child("Name").setValue(name);
mRef.child(key).child("Age").setValue(age);
Each call to setValue gets sent to the Firebase database separately. So you're performing two independent write operations to the database. And each write operation may be sent out to the listeners.
To make them go out as one write operation, combine the two properties into a single call to setValue():
Map<String, Object> values = new HashMap<String, Object>();
map.put("Name", name);
map.put("Age", age);
mRef.child(key).setValue(values);
This will perform a single write to the database, with the same final result. But it will only trigger the listener once.
Update
If we look back at your initial code:
mRef.child(key).child("Name").setValue(name);
mRef.child(key).child("Age").setValue(age);
The first call to setValue causes $key to be created, while the second call merely updates the Age node under it. When using a child listener on mRef, that means that the first call to setValue() triggers onChildAdded, while the second call triggers onChildChanged().

Firebase Database ArrayList is not ordered

Why is the list I retrieve from the Firebase Database not ordered with orderByKey()?
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
transactions = mDatabase.child("balance").child("users").child(userid).child("log").orderByKey();
transactions.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
Map<String, Object> td = (HashMap<String,Object>) snapshot.getValue();
ArrayList<Object> values = new ArrayList<Object>();
values.addAll(td.values());
Log.d("Transactions", values.toString());
}
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
});
The ArrayList "values" is unordered.
This is an example of the structure in json format:
"balance" : {
"users" : {
"log" : {
"-Kp0plO6zBeulHQ8S1Fj" : {
"In" : 100
},
"-Kp0qHM73Mcwbli1gaK6" : {
"Out" : -100
},
"-Kp0qgkORJx5sTi2rUZf" : {
"In" : 100
},
"-Kp1OCdSpUA7SEZhVoPR" : {
"In" : 100
},
"-Kp1OdtuuF6z_zlNj2St" : {
"In" : 100
}
}
}
}
When you retrieve a collection from Firebase, it receives three pieces of information for each child node:
the key of the child
the value of the child
the relative order of the child
When you call snapshot.getValue() in your current code, you tell Firebase to convert this into a Map<String, Object>. Since a Map is unordered, the Firebase client keeps the keys and values but loses the ordering of the children.
To ensure you keep the order, you must use DataSnapshot.getChildren() to process the result:
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
transactions = mDatabase.child("balance").child("users").child(userid).child("log").orderByKey();
transactions.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
ArrayList<Object> values = new ArrayList<Object>();
for (DataSnapshot child: snapshot.getChildren)) {
values.addAll(child.getValue());
}
}
To achieve what you want you need to change this line of code:
transactions = mDatabase.child("balance").child("users").child(userid).child("log").orderByKey();
with
transactions = mDatabase.child("balance").child("users").child(userid).child("log").orderByChild("In");

How to get multiple children with their IDs in one query

I'm trying to add chat feature to an Android App with Firebase Realtime DB as storage.
My schema is something like this,
conversation: {
conversation_id_generated_by_firebase: {
last_message: {
message: "hehe"
type: "text"
attachments: {0: "url", 1: "url"}
likes: {0: "uid1", 1: "uid2"}
created_at: 1245789898
},
messages: {
m1: {
message: "hehe"
type: "text"
attachments: {0: "url", 1: "url"}
likes: {0: "uid1", 1: "uid2"}
created_at: 1245789898
}, m2: {}, m3: {}, m4: {}
},
read_till: {
uid1: 14567894229
uid2: 14567894228
},
created_at: 1456789329
updated_at: 1456789429
},
}
Now, How can I fetch multiple conversations with ids in one query/call?
There is no Firebase equivalent to SQL's SELECT * WHERE id IN (1,2,3). In Firebase you'll retrieve each item separately.
This is not nearly as slow as most developers think, since Firebase can efficiently pipeline such requests over a single connection. See my answer here for a longer explanation (and some ASCII art): Speed up fetching posts for my social network app by using query instead of observing a single event repeatedly
By retrieving ID do you mean you want to retrieve "conversation_id_generated_by_firebase", If yes, i have implemented somewhat similar thing, have modified code as per your DB details. If you could provide some code from what you have tried i can help you further.
ArrayList<String> keyList = new ArrayList<>();
// i am assuming you have Chat Object for each conversation
ArrayList<Chat> chatList = new ArrayList<>();
myRef = database.getReference().child("conversation");
ValueEventListener chatListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//will be called every time a new conversation is added
if(dataSnapshot != null){
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
String key = postSnapshot.getKey();
//store key(your id) in array list
keyList.add(key);
//now i am assuming you have an object of chat message
Chat chat = postSnapshot.getValue(Chat.class);
//add all conversation to chatList ArrayList
chatList.add(chat);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//handle error incase something fails
}
};
myRef.addValueEventListener(chatListener);

Get children with unknown keys in Firebase

I'm making a blog posting app. I need to display the posts with the name of the author and the time.
I'm adding the post to database at posts/uid/key This key is added by Firebase on pushing the values. I cannot set this key to a fixed value as each post has different name, time, and body.
Now while retrieving the data, I want to know how to get the data at posts/uid/key/
I'm using this loop to traverse all the children of posts/ But I cannot go further into the nesting as I don't know what the keys are
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
String uid = (String) postSnapshot.child("uid").getValue();
String body = (String) postSnapshot.child("body").getValue();
}
}
I'm attaching the above listener to this reference
mPostReference = FirebaseDatabase.getInstance().getReference().child("posts");
How do I get the children of the keys without getting what the keys are?
private DatabaseReference mPostReference;
mPostReference = FirebaseDatabase.getInstance().getReference()
.child("posts");
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
String uid = (String) postSnapshot.child("uid").getValue();
String body = (String) postSnapshot.child("body").getValue();
Toast.makeText(getActivity(), body,
Toast.LENGTH_SHORT).show();
}
}
Exported JSON
{
"posts" : {
"-KTGou5X14D8pq1sxyhR" : {
"body" : "first post",
"timestamp" : 1475620339666,
"uid" : "tmFt3NbcnLVlkrWQrIx1"
},
"-KTGp3mfM4krbGoTMZ8t" : {
"body" : "second post",
"likeCount" : 0,
"uid" : "tmFt3NbiwLVlkrWQrIx1"
}
}
}

Categories

Resources