7

I want to paginate my forum posts stored in Firebase by pages of 20 items, like so:

  • User accesses foo.com/1 --> most recent 20 posts are loaded
  • User accesses foo.com/2 --> posts 21-40 are loaded

and so on.

Now I am aware I can work with query cursors (as mentioned here), which works perfectly fine for e.g. infinite scroll, because there I start with page 1->2->3 and so on, and each time I have the last visible document available to reference to in my .startAfter(lastVisible) method.

But what if I want users to be able to access e.g. page 13 to see posts 241-260 directly? Is there a way to start at page document 241, without doing (multiple) queries first to get the lastVisible documents?

Addition:

This is probably very bad, so be carful in implementing the below. I found following way to "solve" this issue:

const pageNo = 1 /* variable */
const postsPerPage = 20

const baseRef = fireDb.collection("posts")

let currentPageRef

if (pageNo === 1) {
  currentPageRef = baseRef.limit(postsPerPage)

} else {

  let lastVisibleRef = baseRef.limit((pageNo-1) * postsPerPage)
  const lastVisibleQuerySnapshot = await lastVisibleRef.get()
  const lastVisiblePost = lastVisibleQuerySnapshot.docs[lastVisibleQuerySnapshot.docs.length-1]

  currentPageRef = baseRef.startAfter(lastVisiblePost).limit(postsPerPage)
}
const currentPageQuerySnapshot = await currentPageRef.get()

That needs two queries. But it achieves what I want to achieve. Can anyone judge how bad that solution is efficiency/billing? E.g. if someone would access page 999 I fear that will be costly?

Pascal
  • 1,661
  • 17
  • 29

2 Answers2

4

With the Firestore client SDKs, there is no ability to specify an offset into query results. You can read a discussion about this on GitHub.

The server SDKs do have offset, however.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Thanks for your fast response. So doing it in Firebase Functions would work? I edited my question and added one solution I found above - could you check if that solution is viable or rather too risky? Much appreciated! – Pascal Aug 13 '18 at 21:05
  • 1
    Sure, you could use Cloud Functions, among other backend choice you have. Any method of offset, both by using offset() on the backend or iterating all the documents is going to cost you a document read for each document skipped. – Doug Stevenson Aug 13 '18 at 21:26
  • 2
    Take care that as per Google pricing you'll be billed for each skipped object. More here: https://github.com/firebase/firebase-js-sdk/issues/479 – M.ES Mar 05 '19 at 13:42
1

I'm trying to solve this, and I think a cloud function that runs daily or weekly and assigns each document a manual order might help you

for example, if you want the documents sorted by rating, then the cloud function will run each day, get the documents by their rating, and and assigns the most ranked document order = 1, 2nd document order = 2 ....

this way, you can query documents 1-10 for page 1, query documents 11-20 for page 2 ....

  • the downside is that you will pay the cost of reading and writing to all the documents every day or week
  • you also need to do this manual order for every sort order ( rank, most viewed ... )
  • and you increase the complexity

but if you simply want the results sorted by most recent, then you can simply assign a manual increasing order for each new document

  • and store the newest document order in an info document
  • so if you have a 100 documents
  • and you want the oldest 10 documents, you will simply get documents ordered 1-10

however, given how little I use google search pages and how little I scroll through a youtube search

  • this might not be worth the effort and the cost

good luck

Ninja Dev
  • 816
  • 8
  • 10