在我的firestore数据库中,有12个以上的文档。我可以通过调用以下函数on button click正确地获取前三个文档。但是在secondclick上,尽管documentReference正确传递,但它没有检索任何数据。querySnapshot大小即将为0。这可能是问题所在。
以下是声明

private val db: FirebaseFirestore = FirebaseFirestore.getInstance()
private val colRef: CollectionReference = db.collection("Notebook")
private var lastResult: DocumentReference? = null
private lateinit var query: Query
以下是onButtonClick代码:
private fun loadNoteNew() {
    @Suppress("SENSELESS_COMPARISON", "LiftReturnOrAssignment")
    if (lastResult == null) {
        query = colRef.orderBy("priority")
            .limit(3)
    } else {
        Log.i(TAG, "Start ${lastResult!!.id}")
        query = colRef.orderBy("priority")
            .startAfter(lastResult)
            .limit(3)
    }

    Log.i(TAG, "before get")
    query.get()
        .addOnSuccessListener { querySnapshot ->
            var data = ""
            Log.i(TAG, "querySnapshot Size : ${querySnapshot.size()}")
            if (lastResult != null) {
                Log.i(TAG, "querySnapshot ID : ${lastResult!!.id}")
            }


            for (snapshot in querySnapshot) {
                val note = snapshot.toObject(Note::class.java)
                note.id = snapshot.id

                val title = note.title
                val desc = note.description
                val priority = note.priority
                data += "${note.id} \nTitle =$title \nDescription = $desc\nPriority : $priority\n\n"
            }
            if (querySnapshot.size() > 0) {
                data += "---------------\n\n"
                textView_loadData.append(data)
                lastResult = querySnapshot.documents[querySnapshot.size() - 1].reference
                Log.i(TAG, lastResult!!.id)
            }
        }
}
下面给出的是首次点击的logcat
I/FireStoreExample: before get
I/FireStoreExample: querySnapshot Size : 3
I/FireStoreExample: P9hIw4Ai7w4IHP6H3ew3
下面是第二次点击的日志
I/FireStoreExample: Start P9hIw4Ai7w4IHP6H3ew3
I/FireStoreExample: before get
I/FireStoreExample: querySnapshot Size : 0
I/FireStoreExample: querySnapshot ID : P9hIw4Ai7w4IHP6H3ew3
请帮我找出问题所在。
谢谢

最佳答案

由于对使用 startAt startAfter 方法的查询分页的语义有误解,第二个查询结果为空。
假设Notebook集合包含N个文档。当您进行第一个查询时,您会要求按优先级字段排序的前三个文档,因此该查询将返回文档1..3。然后,在第二次单击时,您期望查询返回下一个3个结果,因此实际上您期望的是文档4..6。这里的关键点是 startAt start After都是根据有序字段的值而不是最后检索的文档进行分页。总体而言,startAt和startAfter的语义大致如下。
orderby(X).startAt(Y)=>返回X字段大于或等于Y的文档
orderby(X).startAfter(Y)=>返回X字段严格大于Y的文档
考虑到这一点,让我们检查一下执行第二个查询时代码的实际作用:

// At the end of the first query...
lastResult = querySnapshot.documents[querySnapshot.size() - 1].reference

// Second query
query = colRef.orderBy("priority")
            .startAfter(lastResult)
            .limit(3)
在上面的代码中,您要请求“优先级”字段大于文档参考“P9hIw4Ai7w4IHP6H3ew3”的文档,实际上没有大于该文档的文档,因此结果集为空。这都是api reference
还有另一件事要注意。由于这些方法会根据字段值进行过滤,因此光标的位置可能不明确。例如,如果您有4个优先级为3的文档,并且在设置startAfter(3)时已经检索了前三个文档,那么您将丢失一个文档。同样,如果要创建startAt(3),您将取回相同的三个文档。 documentation中也指出了这一点。总而言之,您可以通过两种选择使此工作按预期进行:
在另一个字段中添加另一个orderby,以便文档可以由组合唯一标识,从而防止任何游标歧义,并且可以保证在使用 startAfter 之后使用。下一个代码片段基于doc示例和您的代码。
// first query
query = colRef.orderBy("priority")
              .orderBy("AnotherField")
              .limit(3)
// Save last document
lastResult = querySnapshot.documents[querySnapshot.size() - 1]

// Second and next queries
query = colRef.orderBy("priority")
              .orderBy("AnotherField")
              .startAfter(lastResult)
              .limit(3)
最后,请记住,查询所有文档(如果文档数量不多)可能会更简单,然后将优化推迟到性能成为问题为止。

07-24 17:00
查看更多