0

I'm using firebase for a listing user and I want to retrieve the user based on a number of clicks. I saved the number of clicks into the child key named click. Here you can look at the document structure. I am using the scroll load to list the user. 12 records should be in go as we scroll the record should from 12 to 24.

In short, The user has the most number of click should be on top with limit records.

enter image description here

Here is the little piece of code I am trying to use. Can Firebase do this?

return firebase
.database()
.ref("reachers_by_user_id")
.orderByChild("click")
.startAt(null)
.limitToFirst(12)
.once("value")
.then(snapshot => {
  let reacherdata = [];
  snapshot.forEach(snap => {
    reacherdata.push(snap.val());
  });
  return reacherdata;
});

Thank you

Lalit Mohan
  • 2,685
  • 2
  • 16
  • 16

1 Answers1

1

If you want to retrieve the 12 users with the most clicks, you'd use this query:

firebase.database()
  .ref("reachers_by_user_id")
  .orderByChild("click")
  .limitToLast(12)
  .once("value")
  .then(snapshot => {
    snapshot.forEach(snap => {
      console.log(snap.key+": "+snap.val().click);
    });
  });

If you run this code you'll see it prints (up to) the 12 highest click counts, in ascending order. This is because Firebase Realtime Database queries always sort nodes in ascending order. There is no way to get the result in descending order. For more on this, see:

In your case, you can easily reverse the (up to) 12 results in the callback with:

  .then(snapshot => {
    let results = [];
    snapshot.forEach(snap => {
      results.push(snap);
    });
    results = results.reverse();
  });

To get to the next twelve, or actually the previous 12, you will need to use endAt passing in:

  1. The click value of the lowest value you already got.
  2. The key of that snapshot, which is used to disambiguate in case there are multiple child nodes with the same click value.

So you'd get the top 12 scores with:

var lowestClickValue, lowestKey;
firebase.database()
  .ref("reachers_by_user_id")
  .orderByChild("click")
  .limitToLast(12)
  .once("value")
  .then(snapshot => {
    var isFirst = true;
    snapshot.forEach(snap => {
      console.log(snap.key+": "+snap.val().click);
      if (isFirst) {
        lowestKey = snap.key
        lowestClickValue = snap.val().click
        isFirst = false;
      }
    });
  });

After running this code, the lowestClickValue and lowestKey variables hold the click and key for the lowest node on the current page. You then get the next page with:

firebase.database()
  .ref("reachers_by_user_id")
  .orderByChild("click")
  .endAt(lowestClickValue, lowestKey)
  .limitToLast(13)

Here we request 13 nodes, since there will be one node we already have. You'll need to exclude that node in your client-side code.

Note that pagination in Firebase is non-trivial, but quite consistent once you understand that the API is not based on offsets. I highly recommend studying some of the other questions on the pagination if you are still having problems.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • What about the next 12 ? @Frank – Lalit Mohan Dec 31 '19 at 20:07
  • 1
    I added an explanation of that too. But please spend some time reading up on pagination and Firebase, as you're not the first one to struggle with this. – Frank van Puffelen Dec 31 '19 at 20:33
  • i will do, it has little problem the second page is repeating the first record of previous page. Do i need to splice to avoid duplicacy – Lalit Mohan Jan 01 '20 at 08:18
  • 1
    Good point. I forgot to mention that indeed you need one overlapping node, since the API is `endAt` and not `endBefore`. I added a bit of explanation about it to my answer. – Frank van Puffelen Jan 01 '20 at 16:24
  • Thanks @frank, i was execting that result. To be truth i already implemented the same before you answer. That's why acceptence of your answer was on hold but i will accept now bc you have completed the answer. – Lalit Mohan Jan 01 '20 at 18:20