Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I paginate in descending order by child value with firebase?

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.

like image 497
Tyler Biscoe Avatar asked Jun 24 '16 03:06

Tyler Biscoe


People also ask

How do I order firestore data?

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() .

How do you filter data in Firebase realtime database?

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 .


1 Answers

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!

like image 96
Tyler Biscoe Avatar answered Sep 21 '22 03:09

Tyler Biscoe