Firestore Pagination

firestore

Pagination offers several benefits in user interfaces and data presentation. Firstly, it enhances the user experience by dividing large sets of content into smaller, more digestible portions, allowing users to navigate information effortlessly. This improves usability and makes it easier for users to find specific items or browse a collection. Additionally, pagination reduces the load on servers and improves performance by fetching and displaying only a limited number of items at a time, resulting in faster page load times and improved overall responsiveness. Overall, pagination dramatically improves the efficiency, usability, and performance of applications and websites that deal with large datasets. Let’s go through the Firebase Firestore pagination process.


Set default values for pageSize and page if not provided

  const limit = pageSize || 10;
  const currentPage = page || 1;

Calculate the starting position based on the current page and limit

  const startAt = (currentPage - 1) * limit || 0;

Access the Firestore collection

  const collectionRef = db.collection('<collection>');

  // Get the total count of documents in the collection
  const totalCount = (await collectionRef.get()).size;

  // Construct the initial query to retrieve the first set of data
  const query = collectionRef.orderBy('updatedAt', 'desc').orderBy('id');
  const first = query.limit(currentPage * limit);

  // Execute the query and retrieve the snapshot
  const snapshot = await first.get();

Get the last document in the snapshot to determine the cursor position

  const last = snapshot.docs[startAt === snapshot.docs.length ? startAt - 1 : startAt];

  // Construct the next query using the cursor position and limit
  const next = query.startAt(last.data().updatedAt, last.data().id).limit(limit);

  // Execute the next query and retrieve the updated snapshot
  const querySnapshot = await next.get();

  // Extract the data from the snapshot and store it in an array
  const data = querySnapshot.docs.map((doc) => doc.data());
const paginatedData = async ({ pageSize, page }) => {

  const limit = pageSize || 10;
  const currentPage = page || 1;

  const startAt = (currentPage - 1) * limit || 0;

  const collectionRef = db.collection('<collection>');

  const totalCount = (await collectionRef.get()).size;

  const query = collectionRef.orderBy('updatedAt', 'desc').orderBy('id');
  const first = query.limit(currentPage * limit);

  const snapshot = await first.get();

  const last = snapshot.docs[startAt === snapshot.docs.length ? startAt - 1 : startAt];

  const next = query.startAt(last.data().updatedAt, last.data().id).limit(limit);

  const querySnapshot = await next.get();

  const data = querySnapshot.docs.map((doc) => doc.data());

  return {
    page: currentPage,
    totalCount,
    data,
  };
}

The paginatedData function is designed to implement pagination in Firestore using JavaScript. It accepts an object as an argument with pageSize and page properties, which determine the number of items per page and the current page number, respectively. If these values are not provided, the function sets default values of 10 for pageSize and 1 for page.

To start retrieving the paginated data, the function calculates the starting position based on the current page and the limit. It then obtains a reference to the Firestore collection using the db.collection('<collection>') syntax, where <collection> should be replaced with the desired collection name.

Next, the function retrieves the total count of documents in the collection by calling collectionRef.get() and accessing the size property of the returned snapshot.

To ensure consistent pagination results, the function constructs a query that orders the documents first by updatedAt in descending order and then by id in ascending order.

The initial query is executed with query.limit(currentPage * limit) to retrieve the first set of data based on the current page and limit. The cursor position for the next query is found from the resulting snapshot containing the documents and the last document in the snapshot.

Using the information from the last document, the function constructs the next query using query.startAt(last.data().updatedAt, last.data().id).limit(limit). This query starts at the position defined by the updatedAt and id of the last document and retrieves the next set of data with the specified limit.

Kindly observe that the field specified in the “where” clause and the “orderBy” clause must be identical. Additionally, it is important to note that in certain situations, you might need to create an index, and without it, the operation could fail when using equality operators, among other cases.

Finally, the function extracts the data from the snapshot and stores it in an array. It returns an object containing the current page number, the total count of documents, and the retrieved data.

In summary, this code efficiently implements pagination in Firestore by retrieving data in chunks based on the provided page size and current page number, while also ensuring consistent ordering of results.

Daily writing prompt
What fears have you overcome and how?