meeshaa
meeshaa

Reputation: 163

Pagination for Firebase Realtime database

I have been trying to search for a way to do pagination for Firebase Realtime Database. I see a lot of tutorial/articles on pagination for Cloud Firestore but nothing for Realtime Database. Below is my code and its working as expected. Can anyone point me in the right direction for adding pagination to this? If even possible? Any help would be appreciated.

  const [ufoSightings, setUfoSightings] = useState([]);
  const [userStateSelection, setUserStateSelection] = useState("");

  useEffect(() => {
    let allUfo = [];

    //referencing firebase db
    const ufoRef = firebase.database().ref("ufos");
    //filter database searching for specific state user is looking for
    const query = ufoRef
      .orderByChild("state")
      .equalTo(`${userStateSelection}`)
      .limitToFirst(12);

    query.once("value").then((snapshot) => {
      //storing ufoSightings in state
      snapshot.forEach((snap) => {
        allUfo.push(snap.val());
      });
      setUfoSightings(allUfo);
    });
  }, [userStateSelection]);

Upvotes: 0

Views: 2828

Answers (2)

Sagar Mc
Sagar Mc

Reputation: 19

when I tried Frank van Puffelen's answer to query for the next page, I got an error that says

Error: startAfter: Starting point was already set (by another call to startAt, startAfter, or equalTo).

After going through this firebase documentation here is a query that worked for me to get next page

const query = ufoRef.orderByChild("state")
.startAt(`${userStateSelection}`,lastKey)
.endAt(`${userStateSelection}`).limitToFirst(12)
.once("value");

The only drawback is lastKey's list value will be fetched every time you query for the next page which is redundant, so you have to take care of that.

The reason why it worked for me:

From this firebase documentation

startAt ( value : number | string | boolean | null , key ? : string ) : Query

The starting point is inclusive, so children with exactly the specified value will be included in the query. The optional key argument can be used to further limit the range of the query. If it is specified, then children that have exactly the specified value must also have a key name greater than or equal to the specified key.

endAt ( value : number | string | boolean | null , key ? : string ) : Query

The ending point is inclusive, so children with exactly the specified value will be included in the query. The optional key argument can be used to further limit the range of the query. If it is specified, then children that have exactly the specified value must also have a key name less than or equal to the specified key.

So the query will try to fetch

state >= userStateSelection && state <= userStateSelection (lexicographically)

which will equal to

state == userStateSelection

Upvotes: 2

Frank van Puffelen
Frank van Puffelen

Reputation: 598785

To get the next page, you pass in the state and key of the node to start at or after

So say you capture the values in your listener with this:

var lastState, lastKey;
query.once("value").then((snapshot) => {
  //storing ufoSightings in state
  snapshot.forEach((snap) => {
    allUfo.push(snap.val());
    lastState = snap.val().state; // 👈
    lastKey = snap.key; // 👈
  });
  setUfoSightings(allUfo);
});

Now you can get the next page with this query:

const query = ufoRef
  .orderByChild("state")
  .equalTo(`${userStateSelection}`)
  .startAfter(lastState, lastKey) // 👈
  .limitToFirst(12);

The startAfter() method is relatively new to the Realtime Database, so if you can't find it or are having trouble with it try the (much older) startAt() method with the same arguments.

Also check out some of the many other questions on firebase-realtime-database pagination, as this has been covered here quite frequently already.

Upvotes: 2

Related Questions