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.
Related
I have a firebase database consisting of a bunch of cases. I want to loop through all these cases and find the count of Male cases only, male is represented by "M".
Picture of my database.
How I am trying to query for this data:
databseCOVIDCases = FirebaseDatabase.getInstance().getReference();
databseCOVIDCases.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot data : snapshot.getChildren()) {
if (data.child("Sex").getValue(String.class) == "M") {
numMaleCases++;
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) { }
});
When I set the text of the text view it shows 0 and then crashes with an out of memory error.
Instead of looping through all cases and counting the ones where Sex is M, I'd recommend using a query to only read those nodes. That saves you (and your users) the bandwidth of loading all the nodes where Sex is not M.
In code that'd be:
Query query = databseCOVIDCases.orderByChild("Sex").equalTo("M");
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
Log.i("Cases", "M case count: "+snapshot.getChildrenCount());
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // Never ignore errors
}
});
While the above works, a few things to keep in mind:
Any code that needs the count has to be inside the onDataChange method or be called from there. Other code may not run when you expect it to run.
For more on this, see
getContactsFromFirebase() method return an empty list
and
Setting Singleton property value in Firebase Listener
Reading all these nodes to only show the count it wasteful. It is much more practical (though unusual if you come from a SQL background) to store the actual count you need in the database, and update it whenever you add/remove a M node. While your write operations becomes more complex when you do this, your reads become much simpler, cheaper, and more scalable.
For more on this, see How to get size of an element/list in Firebase without get it all? and Is the way the Firebase database quickstart handles counts secure?
My Realtime Database has achieved over 1GB data stored, so in order to trim it,save storage and optimize daily use once a month i run a routine to delete old and irrelevant data.
it goes like this:
App.getDatabaseInstance().getReference("store/orders/historic/").orderByChild("creationTs").limitToLast(500).endAt(System.currentTimeMillis() - (90L * ONE_DAY_MILLIS)).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChildren()) {
for (DataSnapshot historicDs : dataSnapshot.getChildren()) {
historicDs.getRef().removeValue();
}
cleanHistoricBranch();
} else
System.out.println("FINISHED!!!");
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
The query run over a few thousands nodes (NOT MILLIONS) in the database but it takes HOURS to complete. i guess the problem is that the data must be downloaded and deleted ONE BY ONE
i tried different approaches but didnt work well.
App.getDatabaseInstance().getReference("store/orders/historic/").orderByChild("creationTs").limitToLast(500).endAt(System.currentTimeMillis() - (90L * ONE_DAY_MILLIS)).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChildren()) {
dataSnapshot.getRef().removeValue(); //deletes the whole branch, even the nodes that doesnt match the query.
cleanHistoricBranch();
} else
System.out.println("FINISHED!!!");
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
so does anyone have any better approach to trim large number of nodes in the database hierarchy? each node has very few data, but i have around 20 to 50 thousands of nodes candidates to removal.
If the time is mostly spent reading the data, the common approaches are:
Run the process more frequently, so that you have to do less data each time.
Set up integrated backups of your database, and use that backup to determine the keys to delete offline. Then send the write operations to the online database.
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
I'm using firebase with android to create a simple chat app. When the user chooses another user to chat with I want to check whether they've chatted together or not.
In onCreate() method I'm retrieving all the rooms that the current user used before, and I'm putting them in an arraylist called MyChatRooms<>.
Then I want to check each room to see the users of the room.
The problem is that the loop I'm using to iterate through rooms name is finishing before I'm able to retrieve any data from the database.
I know there's similar questions to mine, but none of the answers worked for me.
Here's the related code:
if (!MYChatRooms.isEmpty()) {
for (j = 0; j < MYChatRooms.size(); j++) {
roomref.child(MYChatRooms.get(j)).child("First User").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot1) {
if (!dataSnapshot1.getValue().toString().equals(Username) && dataSnapshot1.getValue().toString().equals(NUsername)) {
Users += dataSnapshot1.getValue().toString() + ",,, ";
} else if (dataSnapshot1.getValue().toString().equals(Username)) {
roomref.child(MYChatRooms.get(j)).child("Second User").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot2) {
if (dataSnapshot2.getValue().toString().equals(NUsername)) {
Users += dataSnapshot2.getValue().toString() + ",,, ";
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
I would suggest that you change the structure of your data. Imagine if a user has 100 chats that means your have to query 200 times to Firebase that of course does not look feasible.
What i would suggest is that your add a recentChat list in every user and whenever a user starts a new chat with someone you add the id of the second user to that list. That way you can track easily with whom the current user has interacted with.
It structure in firebase can look something like this:
User
recentChats
id of the other user
Try to change you database hierarchy or use firestore instead of real time database
Please check the following topic: https://firebase.google.com/docs/database/usage/optimize?
In my case, I had added and index column and limited the query in Firebase Rules.
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.