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
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.
You can use
startAfter()
withDocumentSnapshot
of last document instead of the timestamp value. Try:Here,
lastReadDocSnap
would besnap.docs[3]
i.e. the last document of previous query.