英文:
Paginaion in firestore: Jump to a specific page without knowing the first document in that page
问题
我有一个包含成千上万个文档的Firestore 集合,我需要实现一个分页系统,具体要求如下:
- 一次只渲染20个文档。
- 文档应该按照一个名为 created_at 的时间戳字段进行排序。
- 用户应该能够直接跳转到指定页,而不需要逐页翻过去。例如,可以直接打开第9页。
以下是你的代码:
import { getDocs, query, collection, orderBy, getFirestore, startAt, limit } from 'firebase/firestore';
const pageSize = 20;
async function fetchPage(page: number){
const db = getFirestore();
const offset = page * pageSize;
const q = query(
collection(db, 'order'),
orderBy('created_at'),
limit(pageSize),
startAt(offset));
return await getDocs(q);
}
fetchPage(9).then(snapshot => {
console.log('加载的文档: ', snapshot.docs);
});
上面的代码总是加载集合中的前20个文档,不管提供的页码是多少,而且无论你传递给 startAt
方法的整数值是什么,都不会影响结果。
英文:
I have a Firestore collection with thousands of documents and I need to implement a pagination system where:
- Only 20 documents will be rendered at a time
- Documents will be sorted by let's say, a created_at timestamp field.
- One more very important requirement is that the user should be able to jump to a specific page directly without having to go through all the previous pages first. For example, open the 9th page directly.
Here's my attempt:
import { getDocs, query, collection, orderBy, getFirestore, startAt, limit } from 'firebase/firestore';
const pageSize = 20;
async function fetchPage(page: number){
const db = getFirestore();
const offset = page * pageSize;
const q = query(
collection(db, 'order'),
orderBy('created_at'),
limit(pageSize),
startAt(offset));
return await getDocs(q);
}
fetchPage(9).then(snapshot => {
console.log('Documents loaded: ', snapshot.docs);
});
The above code always loads the first 20 documents in the collection regardless of the page number and regardless of whatever integer value I provide to the startAt method, it just has no impact on the results.
答案1
得分: 1
你编写的代码不会达到你的意图。相反,它将返回第一个 pageSize
文档,这些文档满足 created_at > offset
的条件。Firestore 客户端中没有偏移量。
但是,根据你的需求,你可以采取以下方式进行一些修改:
- 在每个文档的一个字段中添加文档编号模除 20 的结果,比如
page
。 - 在一个单独的中央文档中保留文档的总数。你需要在每次创建 1 中的文档时递增这个值。
然后,取决于你对 "第 n 页" 的理解:
- 第 n 页是从一开始创建的 20 个文档集合 => 那么很容易,只需在查询中添加
where('page','==',n)
。 - 第 n 页是最新的 20 个文档集合(例如,第 1 页是最后的 20 个文档),那么你需要进行一些数学计算,但通过检索至多 2 个连续的
page
(因此 40 个文档),你始终可以获取到你想要的 20 个文档。
注意:
- 这个解决方案要求你首先读取当前的总文档数,然后创建新文档并递增总数 - 这一切都在一个事务中以避免并发问题。这将限制你可以创建文档的速度。
- 因此,每次操作都会多消耗 1 次读取和 2 次写入。
- 如果可以删除文档,这个解决方案将无法正常工作。
英文:
The code you write will not do what you intend. Instead it will return the first pageSize
documents with created_at > offset
. There is no offset in Firestore client.
But, depending on your needs, you could for instance hack it this way:
- Add the document number modulo 20 in a field of each document, say
page
- Keep the total number of documents in a separate central document. You will need to increment it every time a document in 1 is created.
Then it depends what you mean by page nth:
- the nth set of 20 docs created from the start => then easy, just add
where('page','==',n)
to your query. - the nth set of 20 latest documents (eg page 1 = 20 last documents) then you will have to to some math but by retrieveing documents for at most 2 consecutive
page
(so 40 docs) you are always sure to get the 20 you want.
Note that
- this solution requires that you first read the current total document number and then create the new document and increment the total number - all this in a transaction to avoid concurrent issues. This will limit the rate at which you can create documents.
- Consequently it will cost you 1 more read and 2 more write each time
- This solutions does not work if you can delete documents
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论