I use Firebase database on my Android app. Normally, it works fine. But when the database is getting larger, the query performance is getting worse. I added about 5k record on database (under "elk" and "su" nodes), then I queried on database (on "cut" and "user" nodes) but all the queries are very very slow. I defined data index on database rules but it did not work. How can I solve that problem?
Here are my queries :
// query to get the zones followed by user
FirebaseDatabase.getInstance()
.getReference()
.child("user")
.child(userID)
.child("zones");
// query to get cuts on a zone
FirebaseDatabase.getInstance()
.getReference()
.child("cut")
.child(cutType)
.orderByChild("zoneID")
.equalTo(zoneID);
If you want to continue expanding the best thing to do would be to duplicate your data in a zone reference where it knows which elk/su are a part of it. Something like this:
{
zones: {
elk: {
"istan-besik": {
"-KSp)bL5....": true,
...: true
}
}
}
}
That way when you want to search for all you would just do:
...child('zones').child(zoneId).child(cutType)
And then loop through those to go get each elk/su directly
Related
I want to query my Workout Collection for the latest workout from a routine. Meaning I query with whereEqualTo my routineKey, order it by the Started TimeStamp in descending order and then limit to 1 and then take the this 1st Key/Id of the Workout.
However this does not work. whereEqualTo and orderBy work separately but not combined. What am I doing wrong?
fm.getColRefWorkout().whereEqualTo("routineKey", routineKey).orderBy("startTimeStamp", Query.Direction.DESCENDING).limit(1).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
workoutKey = documentSnapshots.getDocuments().get(0).getId();
//To stuff with this workoutKey
}
});
This query will not work unless you create an index for it. This can be done, by creating it manually in your Firebase Console or if you are using Android Studio, you'll find in your logcat a message that sounds like this:
FAILED_PRECONDITION: The query requires an index. You can create it here: ...
You can simply click on that link or copy and paste the URL into a web browser and your index will be created automatically.
I'm developing an app that has a video and an article feed. I implemented swipe refresh layout. Whenever user swipes it, it loads last 5 video datas from Firebase.
My database is like this (it's not much data) =>
Swipe refresh layout listener =>
mSwipeRefreshLayout.setOnRefreshListener(() -> {
manager.scrollToPosition(0);
refreshVideoFeed();
});
And refreshVideoFeed method triggers this =>
Query query = myRef.orderByChild("videoDate").limitToLast(5);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
..................
It works fine. However, I realized that app is using lots of data when i looked at Realtime Database dashboard (even app is not in product)
Then I opened Profiler in Android Studio to see what is going on. I ordered by child 'videoDate' and got last 5 videos. It costs 76 KB for refreshing video feed.
Then again I ordered by child 'videoDate' and got last 20 videos. Again it costs 77KB !
Also, I implemented the same mechanism for article feed. I have 236 articles in my realtime database. Whenever user swipes, it loads 10 articles and it costs 3,6 MB!
I wonder why this is happening and how to avoid that. It seems Firebase SDK fetchs all Videos to client and then filters them. But I want to fetch only specific range of data that I specified.
Ordering and filtering data is only done on the Firebase servers if there's an index defined on the property/value you filter on. If there's no index, the server sends all data to the client, which then orders and filters it. There should a quite explicit message in the log output when this happens.
To define an index, you go to the security rules panel in your Firebase console and on the node that myRef points to add an .indexOn property. Say myRef refers to /articles, it'd look something likeL
{
"rules": {
"articles": {
".indexOn": "videoDate"
}
}
}
If you order/filter on different properties, you can add multiple indexes:
".indexOn": [ "videoDate", "category" ]
I am making a challenges between users in my app .I am trying to get the last 15 users who enters in challenges. I store the time each time the users enter a new challenge. The query was working well in the begging but after that it stops showing new users and only old users appears in it.
this is the query code :
usersReference.orderByChild("lastChallengeDate")
.limitToLast(15)
.addListenerForSingleValueEvent(new ValueEventListener()
and this is the database structre of the user child :
When I opened the log I found this warn although I am using index on in my rules
W/PersistentConnection: pc_0 - Using an unspecified index. Consider adding '".indexOn": "lastChallengeDate"' at users to your security and Firebase Database rules for better performance
If you perform a query on a location, Firebase sorts the children under that location on the property you specify. There is no value in lastChallengeDate directly under each child of users. Instead the property is under lastChallengeDate/time, so you should order on that
usersReference.orderByChild("lastChallengeDate/time")
.limitToLast(15)
.addListenerForSingleValueEvent(new ValueEventListener()
You also need to define an index on users (or whatever the name is of the node you query):
{
"rules": {
"users": {
".indexOn": "lastChallengeDate/time"
}
}
}
Be sure to also study:
the documentation on queries, which includes an example of querying such a nested property
the documentation on defining indexes
some of the many questions with the same error message
I am making a sample android app which shows all data present inside Firebase Database with the help of RecyclerView. It is working as I expected. Issue Is If I add More Items In Database As Time Passes. It would still get all data and show in recyclerView. It would be definitely slow (Due to internet and slow performance Of Devices) and would take some time to show data on recyclerView.
I heard of a way to resolve this by making them small chunks and loading another one when user scrolls further. This Process is known as pagination.
But In case Of Firebase Database, there is no direct way to paginate data in recyclerView. I have also searched for this issue on internet but none of them work.
Has anyone idea how to paginate firebase database data in recyclerView?.
Pagination Can Be Understood By This Sample Video
to do so you need to define two type of lists. One for major list which have all the elements and second one which have limit data.
private Query getQuery(String query) {
Query query;
if (recentLastItem == null) // recent last item is the any type of object which you have stored in the firebase
query = FirebaseDatabase.getInstance().getReference()
.child(your saved data location)
.orderByKey()
.limitToLast(no of elements per time you want);
// this if call when you try first time to get the items from firebase
else
query = FirebaseDatabase.getInstance().getReference()
.child(your save data location)
.orderByKey()
.startAt(recentLastItem)
.limitToFirst(no of items);
// this else part run when you try to get next no of items
return query;
}
get this query object and call value Listner on it. and one More thing you need to call getQuery() method whenever user reach the end screen of the device.
And do not forgot to update the value of last element from your list after seting the recyclerView.setAdapter(adapter) by calling recentLastItem = yourListName.get(yourListName.size() -1)
I want to SELECT * FROM products WHERE 'birthday' = true;
But can I do the same with Firebase Database ?
I have tried
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref. child("products").orderByChild("birthday").equalTo(true).addChildEventListener ........
Firebase Database image
But it doesn't work.Please help.
f my data structure is bad, please also advise how to create a better structure.
The screenshot of the database shows that birthday is not a direct child of the product node: there's an extra step, for_purpose.
Your query must follow the schema precisely, therefore update your query code like this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
ref.child("products")
.orderByChild("for_purpose/birthday")
.equalTo(true)
.addChildEventListener ...
Note that for this to work effectively, you must set up indexes for every possible for_purpose child in your security rules. Or at least for those that you use in queries. The indexes must match your query exactly, putting an index on for_purpose is not enough.
For this question, you need at least the following:
{
"rules": {
"products": {
".indexOn": [
"for_purpose/birthday",
"for_purpose/anniversary",
"for_gender/male",
...
]
}
}
}