Write any query using startAt() or startAfter() methods. They are supposed to move the query cursor to the specified position. But they don't work at all. The result of a query does not depend on the values passed to startAt() / startAfter(), the cursor is always set on the 0 index.
https://stackblitz.com/edit/firebase-issue-sandbox-bi2zx3
const startAt = 10; // Choose any value. The result of the query is always the same. The value is ignored.
const limit = 10;
const ref = db.collection('companies')
.orderBy('name')
.startAt(startAt)
.limit(limit)
.get()
.then((data) => {
// Always returns the same set of results.
// No matter what the `startAt` value is the query aleays returns as it was `0`
});
I can't run your example due to permissions, but from the code, I think you are expecting startAt() and startAfter() to work as an offset, but that's not in fact what they do. Given an ordered list of documents, they let you move to the document with a specific _field value_ in the list (not to a numeric offset within the list).
So for your example you'd need to do something like orderBy('name').startAfter('three') to skip to the entries with a name field that is > 'three'.
Hope this helps. Unfortunately there's no way to do an arbitrary numeric offset via the Cloud Firestore SDK as there's no way for the backend to efficiently implement this. It would still have to read every document that you're trying to skip, which is slow and expensive.
@mikelehen
Omg. So I misunderstood the documentation completely!. Examples given in the docs are a bit misleading.
For example this one:
citiesRef.orderBy("population").startAt(1000000)
I missed the fact that the field is named population, so I thought that 1000000 is an index, not a field value.
Thanks for the explanation, but IMO the documentation should be more clear about it.
Thanks for the feedback! We'll take a look at how we can improve the documentation and example code snippets to be clearer on our next revision of that doc.
I think you are expecting startAt() and startAfter() to work as an offset, but that's not in fact what they do.
So is this why the docs user a variable "lastVisible" to reference the last document returned to use as a starting point?
@jefelewis Yes, that is correct.
Thank you! It鈥檚 a very subtle detail that the docs don鈥檛 mention in enough detail
The documentation is still very confusing, and I was also confused by this discussion. The confusing thing for me was that startAt can take both a DocumentSnapshot or one or more field values. I was trying to use a DocumentSnapshot, but that gave me only EntityTooLarge errors (probably because a document snapshot can be quite large), but when I started using a field value I finally got my code working.
@daniel You shouldn't be getting EntityTooLarge when using startAt with a DocumentSnapshot. Would you mind sharing the debug logs from when this happened? Ideally create a new issue for that.
Most helpful comment
@mikelehen
Omg. So I misunderstood the documentation completely!. Examples given in the docs are a bit misleading.
For example this one:
I missed the fact that the field is named
population, so I thought that1000000is an index, not a field value.Thanks for the explanation, but IMO the documentation should be more clear about it.