I have a firebase collection with over 200k documents in it. I am trying to query this data in batches of 500. I get the first 500 documents back but I cant get the next batch of documents. Also I would lie when I click the previous button, I get the previous batch. Any help will truly be appreciated. Thank you good people!
Here is my code for the component fetching data:
import React, { useEffect, useState } from "react";
import {
collection,
getDocs,
query,
startAfter,
limit,
} from "firebase/firestore";
import { db } from "../../firebase/firebase";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
import TablePagination from "@mui/material/TablePagination";
import ClearIcon from "@mui/icons-material/Clear";
import CheckIcon from "@mui/icons-material/Check";
import EnhancedTableHead from "./usersTableHead";
import { EnhancedTableToolbar } from "./usersToolbar";
function descendingComparator(a, b, orderBy) {
if (b[orderBy] < a[orderBy]) {
return -1;
}
if (b[orderBy] > a[orderBy]) {
return 1;
}
return 0;
}
function getComparator(order, orderBy) {
return order === "desc"
? (a, b) => descendingComparator(a, b, orderBy)
: (a, b) => -descendingComparator(a, b, orderBy);
}
function stableSort(array, comparator) {
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) => {
const order = comparator(a[0], b[0]);
if (order !== 0) {
return order;
}
return a[1] - b[1];
});
return stabilizedThis.map((el) => el[0]);
}
export default function Clients() {
const [rows, setRows] = useState([]); // table rows
const [order, setOrder] = useState("asc");
const [orderBy, setOrderBy] = useState("name");
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
// pull data from firebase and set table rows
useEffect(() => {
const getUsers = async () => {
//query the first 500 docs
const firstUsers = await getDocs(
query(collection(db, "users"), limit(500))
);
// get last visible doc
const lastVisibleDoc = firstUsers.docs[firstUsers.docs.length - 1];
firstUsers.forEach((user) => {
setRows((row) => [
...row,
{
id: user.data().idNumber,
registered: user.data().dateRegistered?.toDate().toDateString(),
firstName: user.data().firstName,
lastName: user.data().lastName,
email: user.data().email,
idNumber: user.data().idNumber,
phoneNumber: user.data().phoneNumber,
loanLimit: user.data().loanLimit,
deviceModel: user.data().deviceModel,
isQualified: user.data().qualified,
},
]);
});
// get the next 500 docs after the last one
const next = await query(
collection(db, "users"),
startAfter(lastVisibleDoc),
limit(500)
);
console.log("next", next);
next?.forEach((user) => {
setRows((row) => [
...row,
{
id: user.data().idNumber,
registered: user.data().dateRegistered?.toDate().toDateString(),
firstName: user.data().firstName,
lastName: user.data().lastName,
email: user.data().email,
idNumber: user.data().idNumber,
phoneNumber: user.data().phoneNumber,
loanLimit: user.data().loanLimit,
deviceModel: user.data().deviceModel,
isQualified: user.data().qualified,
},
]);
});
};
getUsers();
}, []);
console.log("users: ", rows);
const handleRequestSort = (event, property) => {
const isAsc = orderBy === property && order === "asc";
setOrder(isAsc ? "desc" : "asc");
setOrderBy(property);
};
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
const emptyRows =
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - rows.length) : 0;
return (
<div className="">
<EnhancedTableToolbar />
<TableContainer component={Paper}>
<Table sx={{ minWidth: 750 }}>
<EnhancedTableHead
order={order}
orderBy={orderBy}
onRequestSort={handleRequestSort}
rowCount={rows.length}
/>
<TableBody>
{stableSort(rows, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => (
<TableRow
hover
key={index}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
tabIndex={-1}
>
<TableCell align="left">{row.registered}</TableCell>
<TableCell align="left">{row.firstName}</TableCell>
<TableCell align="left">{row.lastName}</TableCell>
<TableCell align="left">{row.email}</TableCell>
<TableCell align="left">{row.idNumber}</TableCell>
<TableCell align="left">{row.phoneNumber}</TableCell>
<TableCell align="left">{row.loanLimit}</TableCell>
<TableCell align="left">
{row.deviceModel === undefined
? "Not Provided"
: row.deviceModel}
</TableCell>
<TableCell align="left">
{row.isQualified ? <CheckIcon /> : <ClearIcon />}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 25, 50, 100]}
component="div"
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</div>
);
}