skip to Main Content

TLDR; firestore skips all the documents that has same startAfter value. How to overcome this limitation.

My firestore postLikers collections keeps a document for each person who liked my post.
It stores the UID of the liker, and the epoch timestamp of when the post was liked.

postLikersCol : [
  doc_1 : { uid: uid1, timeOfLike: 1661924000 },
  doc_2 : { uid: uid2, timeOfLike: 1661924001 },
  doc_3 : { uid: uid3, timeOfLike: 1661924002 }, // same time
  doc_4 : { uid: uid4, timeOfLike: 1661924002 }, // same time
  doc_5 : { uid: uid5, timeOfLike: 1661924002 }, // same time
  doc_6 : { uid: uid6, timeOfLike: 1661924003 },
  doc_7 : { uid: uid7, timeOfLike: 1661924004 },
]

and I am readin the data like this :

firestore()
.collection('postLikersCol')
.orderBy('timeOfLike', 'desc')
.startAfter(lastReadDoc.timeOfLike)
.limit(3)
.get()

In the first round of query the .startAfter() is not added so I get last 3 docs (doc_7, doc_6, doc_5, in this order)

In the second call, .startAfter() is added in query and it takes timeOfLike of the last read document (doc_5) i.e. 1661924002
With this call, the firestore returns doc_2 and doc_1, both of which has timeOfLike < 1661924002

With this scenario, doc_4 and doc_3 are never read !!

Can someone suggest a solution for this, that I can read all documents with .orderBy('timeOfLike', 'desc')


Only solution I thought is using unique orderBy fields.
So appending uid with timestamp may work (1661924002_uid3).
Is there a better solution ?

2

Answers


  1. Chosen as BEST ANSWER

    OK, so I found that that i can give two orderBy and two startAfter, to overcome this issue.

    https://firebase.google.com/docs/firestore/query-data/query-cursors#set_cursor_based_on_multiple_fields

    I suppose it will require a compound index (additional cost overhead) But the solution of appending uid to the timestamp also costs more storage, and lengthier data is stored and it's not a number anymore.

    Hmm, If you still have a better answer please let me know.


  2. You can use startAfter() with DocumentSnapshot of last document instead of the timestamp value. Try:

    const snap = await firestore()
      .collection('postLikersCol')
      .orderBy('timeOfLike', 'desc')
      .startAfter(lastReadDocSnap)
      .limit(3)
      .get()
    

    Here, lastReadDocSnap would be snap.docs[3] i.e. the last document of previous query.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search