I am working on the app where I need to pull specific value from the firebase. For this case I need to pull "Score" where "uID" equals current User id. What would be a best way to do so.
Thank you for any help.
Firebase will always return full nodes. So you cannot just return the score for a user. But you can return the common node that both the score and user are under (the one starting with -K...) by using a Firebase query:
DatabaseReference leadersRef = FirebaseDatabase.getInstance().getReference("Leaders");
Query query = leadersRef.orderByChild("uID").equalTo("vUdnKx...");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot child: snapshot.getChildren()) {
System.out.println(child.getKey()+": "+child.child("Score").getValue(Long.class));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "onCancelled", databaseError.toException());
// ...
}
})
Note that the code loops over the snapshot in the result. That is because a query will potentially have 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.
For more reading see the Firebase documentation on handling lists and sorting and filtering data.
Related
I am designing an application using android studio and firebase. Please see the structure of my database here:
Here I have a parent Sellers node in that seller id as immediate child. Each seller Id contains the details of the seller like name, Shop Type and token.
Here in figure I have shown two sellers with shop type as CarshowRoom and one is having ShopType as supermarket (Actually there are many sellers and want to loop through all sellers).
I like to retrieve device token of sellers if they have a particular ShopType, for example if the seller have ShopType as car showroom I like to get the value of token.
For that I write the code like
query=sellerRef.child("Sellers").orderByChild("ShopType").equalTo("CarShowRoom");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
String sellerToken= snapshot.child("token").getValue().toString();
Toast.makeText(SendEnquiryActivity.this, sellerToken, Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
But my code is not working, any body please help
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 will need to handle this list, by looping over snapshot.getChildren with something like this:
query=sellerRef.child("Sellers").orderByChild("ShopType").equalTo("CarShowRoom");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot child: snapshot.getChildren()) { // 👈 Add this loop
String sellerToken= child.child("token").getValue(String.class); // 👈 Read values like this
Toast.makeText(SendEnquiryActivity.this, sellerToken, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // 👈 Never ignore errors
}
});
Reading the documentation, It seems childEventListener does not fire when the path does not exist.
This is a problem since I want to display a message to the user that there is no data.
I could add a valueEventListener like in this answer but I'm limiting the query to the latest value i.e query.limitToLast() and a valueEventListener doesn't limitTolast but gets all the data in the path.
Example, I have:
posts
{
$userid
{
$postid {
post_content:content
timestamp:1234567
}
$postid {
post_content:content
timestamp:1234567
}
$postid {
post_content:content
timestamp:1234567
}
$postid {
post_content:content
timestamp:1234567
}
}
}
I'm only interested in the latest post so I do firebaseRef.child(users).child(userid).limitToLast(1).addChildEventListener but the user might not have posts yet and childEventListener does not fire in that case.
If you want to handle both the children and the case where no children exists, you can add both a value and a child listener:
Query query = firebaseRef.child(users).child(userid).limitToLast(1);
query.addChildEventListener(new ChildEventListener() {
void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
...
}
...
});
query.addValueEventListener(new ValueEventListener() {
void onDataChange(DataSnapshot snapshot) {
if (!snapshot.exists()) {
// TODO: handle the "no data available" scenario
}
});
});
The Firebase client is smart enough to only load data once, even if there are multiple listeners like in the above case.
If you want, you can also accomplish this with a single ValueEventListener like this:
query.addValueEventListener(new ValueEventListener() {
void onDataChange(DataSnapshot snapshot) {
if (!snapshot.exists()) {
// TODO: handle the "no data available" scenario
}
else {
for (DataSnapshot childSnapshot: snapshot.getChildren()) {
// TODO: handle the child snapshot
}
}
});
});
Since we now get all matching child nodes in snapshot, we loop over the snapshot.getChildren() to get the same data as in onChildAdded.
Since its impossible to attach a listener to a non existing path, you could try adding a property to your user that sets the number of posts he has. Add a listener to that property and if it changes, then you are certain that indeed the user has a path reference in posts, then you can add a listener to that node and get the query every time a child is added with .childAdded .
I'm developing an app. The app must able to show the latest 10 registered user detail from real-time database. That is, It removes any user older than latest 10 users. Is there any way I can do this? Right now my app is able to access the user details stored in realtime firebase.
Thanks in advance.
That sounds totally feasible. An incredibly simple way is to retrieve 11 users in your app, and then just remove the last one.
ref.orderByChild("descending_timestamp").limitToFirst(11).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int userCount = 0;
for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
if (userCount++ > 10) {
userSnapshot.getRef().remove();
} else {
// TODO: show the user in your app
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "load users", databaseError.toException());
}
});
You'll note that I order on descending_timestamp, which is a property that you must add to the data and that allows you to sort the users in reverse chronological order. For more on this, see Firebase Data Desc Sorting in Android
In my Application I am using Firebase to retrieve the mobilnumbers of the Users. Therefore I use this code:
databaseUsers.orderByChild("uid").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
users.clear();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
User contactlists = postSnapshot.getValue(User.class);
users.add(contactlists);
}
ContactList contactAdapter = new ContactList(ContactListActivity.this, users);
listViewContacts.setAdapter(contactAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Now I have the following question: If the number of users is high, is there a possibility to send only the mobilnumbers of your Phonebook maybe in a list? Otherwise I think the traffic to Firebase might be not so efficient?!
The other opportunity would be to send each number individually but this might be quite complex if the user has many contacts.
At the moment I get all numbers from the server but I need to filter for the right contacts AND I need to display the names of the contact.
What is the best solution to use Firebase as efficient as possible and also get the names of the contacts?
Thank you in advance!
You'll have to:
Loop through the local phone book to find the phone number of each contact.
Execute a query to Firebase for each number.
Add the resulting contact (if any) to the list/adapter and update the view.
So say you've done step 1 and have a list of phone numbers. You'd then loop through those and for each:
for (String phonenumber: phonenumbers) {
Query query = databaseUsers.orderByChild("phonenumber").equalTo(phonenumber);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User contactlists = postSnapshot.getValue(User.class);
users.add(contactlists);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore erors
}
});
}
The call to notifyDataSetChanged() ensures that the adapter know that it needs to update the view.
While the code gets a bit convoluted, it is not as slow as you may initially fear, since Firebase pipelines the requests over a single connection. The performance will mostly depend on the number of users you have in the database, but up to a few hundreds of thousands this should be fine.
Reading the documentation, It seems childEventListener does not fire when the path does not exist.
This is a problem since I want to display a message to the user that there is no data.
I could add a valueEventListener like in this answer but I'm limiting the query to the latest value i.e query.limitToLast() and a valueEventListener doesn't limitTolast but gets all the data in the path.
Example, I have:
posts
{
$userid
{
$postid {
post_content:content
timestamp:1234567
}
$postid {
post_content:content
timestamp:1234567
}
$postid {
post_content:content
timestamp:1234567
}
$postid {
post_content:content
timestamp:1234567
}
}
}
I'm only interested in the latest post so I do firebaseRef.child(users).child(userid).limitToLast(1).addChildEventListener but the user might not have posts yet and childEventListener does not fire in that case.
If you want to handle both the children and the case where no children exists, you can add both a value and a child listener:
Query query = firebaseRef.child(users).child(userid).limitToLast(1);
query.addChildEventListener(new ChildEventListener() {
void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
...
}
...
});
query.addValueEventListener(new ValueEventListener() {
void onDataChange(DataSnapshot snapshot) {
if (!snapshot.exists()) {
// TODO: handle the "no data available" scenario
}
});
});
The Firebase client is smart enough to only load data once, even if there are multiple listeners like in the above case.
If you want, you can also accomplish this with a single ValueEventListener like this:
query.addValueEventListener(new ValueEventListener() {
void onDataChange(DataSnapshot snapshot) {
if (!snapshot.exists()) {
// TODO: handle the "no data available" scenario
}
else {
for (DataSnapshot childSnapshot: snapshot.getChildren()) {
// TODO: handle the child snapshot
}
}
});
});
Since we now get all matching child nodes in snapshot, we loop over the snapshot.getChildren() to get the same data as in onChildAdded.
Since its impossible to attach a listener to a non existing path, you could try adding a property to your user that sets the number of posts he has. Add a listener to that property and if it changes, then you are certain that indeed the user has a path reference in posts, then you can add a listener to that node and get the query every time a child is added with .childAdded .