6

Is there a way to fetch document after documentID like

private fun fetchCollectoionnAfterDocumentID(limit :Long){

        val db = FirebaseFirestore.getInstance()
        var query:Query = db.collection("questionCollection")
            .startAfter("cDxXGLHlP56xnAp4RmE5") //
            .orderBy("questionID", Query.Direction.DESCENDING)
        .limit(limit)

        query.get().addOnSuccessListener {
            var questions = it.toObjects(QuestionBO::class.java)
            questions.size
        }
    }

I want to fetch sorted questions after a given Document ID. I know I can do it using DocumentSnapShot. In order to fetch the second time or after the app is resume I have to save this DocumentSnapshot in Preference.

Can It be possible to fetch after document ID?

startAfter - > cDxXGLHlP56xnAp4RmE5

Edit I know I can do it using lastVisible DocumentSnapshot . But I have to save lastVisible DocumentSnapshot in sharedPreference.

When app launch first time 10 question are fetched from questionCollection. Next time 10 more question have to be fetched after those lastVisible. So for fetching next 10 I have to save DocumentSnapshot object in sharedPreference. Suggest me a better approach after seeing my database structure.

And one more thing questionID is same as Document reference ID.

enter image description here

Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300

3 Answers3

9

There is no way you can pass only the document id to the startAfter() method and simply start from that particular id, you should pass a DocumentSnapshots object, as explained in the official documentation regarding Firestore pagination:

Use the last document in a batch as the start of a cursor for the next batch.

first.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
            @Override
            public void onSuccess(QuerySnapshot documentSnapshots) {
                =// Get the last visible document
                DocumentSnapshot lastVisible = documentSnapshots.getDocuments()
                        .get(documentSnapshots.size() -1);

                // Construct a new query starting at this document,
                Query next = db.collection("cities")
                        .orderBy("population")
                        .startAfter(lastVisible) //Pass the DocumentSnapshot object
                        .limit(25);

                // Use the query for pagination
            }
        });

See, here the lastVisible is a DocumentSnapshot object which represents the last visible object. You cannot pass only a document id. For more information, you can check my answer from the following post:

It's in Java but I'm confident you can understand it and write it in Kotlin.

Edit:

Please consider defining an order of your results so that all your pages of data can exist in a predictable way. So you need to either specify a startAt()/startAfter() value to indicate where in the ordering to begin receiving ordered documents or use a DocumentSnapshot to indicate the next document to receive, as explained above.

Another solution might be to put the document id into the document itself (as a value of a property) and order on it, or you can use FieldPath.documentId() to order by the id without having to add one.

You can also check this and this out.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Please see my updated answer for more clarifications. – Alex Mamo Dec 05 '19 at 12:02
  • Hi Xar E Ahmer! Can I help you with other information? – Alex Mamo Dec 06 '19 at 08:55
  • I have added my database structure. See edit section. I have to save lastVisible DataSnapshot to retrieve next records when app launch next time – Zar E Ahmer Dec 09 '19 at 07:02
  • That's very good. Have you tried the paging algorithm explained in **[this](https://stackoverflow.com/questions/50741958/how-to-paginate-firestore-with-android)** answer? Does it work? – Alex Mamo Dec 09 '19 at 07:56
6

There is one way to let startAfter(documentID) works.

Making one more document "get", then using the result as startAfter input.

val db = FirebaseFirestore.getInstance()

// I use javascript await / async here
val afterDoc = await db.collection("questionCollection").doc("cDxXGLHlP56xnAp4RmE5").get();

var query:Query = db.collection("questionCollection")
 .startAfter(afterDoc)
 .orderBy("questionID", Query.Direction.DESCENDING)
 .limit(limit)
Andy
  • 701
  • 1
  • 7
  • 7
0

A simple way to think of this: if you order on questionID you'll need to know at least the value of questionID of the document to start after. You'll often also want to know the key, to disambiguate between documents with the same values. But since it sounds like your questionID values are unique within this collection, that might not be needed here.

But just knowing the key isn't enough, as that would require Firestore to scan its entire index to find that document. Such an index scan would break the performance guarantees of Firestore, which is why it requires you to give you the information it needs to perform a direct lookup in the index.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807