Let's say I have some data as follows:
{
"name": "post #1",
"votes": 100
},
{
"name": "post #2",
"votes": 10000
},
{
"name": "post #3",
"votes": 750
}
And so on.
The data in firebase is not ordered by votes obviously, it's order by key.
I'd like to be able to paginate this data by the number of votes in descending order.
I think I'd have to do something like:
ref.orderByChild('votes')
.startAt(someValue)
.limitToFirst(someOtherValue)
.once('value', function(snapshot) {
resolve(snapshot);
});
Or perhaps, I'd need to use limitToLast
, and endAt
?
Pagination by key
is quite easy, but this one is stumping me.
Update (2017-10-16): Firebase recently announced Firestore - their fully managed NoSQL datastore which should make it easier to do more complex queries. There may still be some use cases where one might use the Realtime database they've always provided. If you're one of those people this question should still apply.
By default, a query retrieves all documents that satisfy the query in ascending order by document ID. You can specify the sort order for your data using orderBy() , and you can limit the number of documents retrieved using limit() .
We can filter data in one of three ways: by child key, by key, or by value. A query starts with one of these parameters, and then must be combined with one or more of the following parameters: startAt , endAt , limitToFirst , limitToLast , or equalTo .
I posted this question after a long day of coding and my brain was mush.
I took another crack at it this morning, and as is so often the case, was able to find the solution rather quickly.
Solution:
In order to paginate data, we need the ability to arbitrarily pull sorted data from the middle of a list. You can do this using the following functions provided by the firebase API:
startAt
endAt
limitToFirst
limitToLast
More information can be found here.
In my case, since I need my data in descending order, I'll use endAt
and limitToLast
.
Assuming I'd like each of my pages to have five items. I would write my first query like so:
ref.orderByChild('votes')
.limitToLast(5)
.once('value', function(snapshot) {
console.log('Snap: ', snapshot.val());
});
This gets the 5 items with the highest number of votes.
In order to get the next page, we'll need to store two pieces of data from the results of our last query. We need to store the number of votes, and key for the item that had the least number of votes. That is to say, the last item in our list.
Using that data, our next query, and all subsequent queries, would look as follows:
ref.orderByChild('votes')
.endAt(previousVoteCount, previousKey)
.limitToLast(5)
.once('value', function(snapshot) {
console.log('Snap: ', snapshot.val());
});
You'll notice in this query I added endAt
. This gets the next 5 items with the most votes starting from the last one in the previous list. We must include the the key for the last item in the previous list so that if there are multiple items with the same number of votes, it'll return a list beginning with the correct item, and not the first one it finds with that number of votes, which could be somewhere in the middle of the list you got from the initial query.
That's it!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With