javascriptfirebasegoogle-cloud-firestore

Firestore snapshot cursor with timestamp vs document


I have an infinite scroll list in my app. On page load, I subscribe to the initial 50 items and then when a users scroll down I subscribe to the next 50 items and so on.

const firestoreQuery = query(
collectionGroup(firestore, 'users'),
orderBy('createdAt', 'desc'),
startAfter(Timestamp.fromDate(new Date(startValue))), // empty on first call
limit(50));

My plan was to use the above query (without startAfter statement on initial call), save the last seen item and then pass the createdAt of last seen item in subsequent calls.

The docs also seem to lean towards passing not the date but entire last document snapshot as the query cursor. Why is this better, does this solve any problems that the first approach has?

NOTE: As you scroll the list, new items can be added and need to appear in the list.


Solution

  • Consider if your ordered result set looked like this (with integers instead of timestamps):

    10
    20
    30
    40
    40
    40
    40
    40
    50
    50
    

    If you limit(5) for the first page, you're going to cut off the batch for fours in the middle, so your first page of 5 looks like this:

    10
    20
    30
    40
    40
    

    Now, say you want to get the second page of 5 documents, so you pass the last seen value startAfter(40). That would skip the next few documents with a value of 40, and start at 50. As a result, your paging would skip several documents entirely that should be in your list. That's why you're supposed to use document snapshots for pagination instead of field values. The document snapshots give you an unambiguously specific index into to correct page of results without the possibility of missing documents like this.