【问题标题】:Firestore query StartAt(DocumentReference) not giving proper resultFirestore 查询 StartAt(DocumentReference) 没有给出正确的结果
【发布时间】:2020-06-28 03:33:15
【问题描述】:

在我的 Firestore 数据库中,有 12 个以上的文档。我通过调用以下函数 on button click 正确获取了前 3 个文档。但是在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

下面给出的是第二次点击的logcat

I/FireStoreExample: Start P9hIw4Ai7w4IHP6H3ew3
I/FireStoreExample: before get
I/FireStoreExample: querySnapshot Size : 0
I/FireStoreExample: querySnapshot ID : P9hIw4Ai7w4IHP6H3ew3

请帮我找出我哪里弄错了。 谢谢

【问题讨论】:

标签: android firebase kotlin google-cloud-firestore


【解决方案1】:

第二个查询结果是空的,因为对使用startAtstartAfter方法的查询分页的语义有误解。

假设 Notebook 集合包含 N 个文档。当您进行第一个查询时,您要求的是按优先级字段排序的前 3 个文档,因此查询返回文档 1..3。然后在第二次单击时,您期望查询返回接下来的 3 个结果,因此您确实期望文档 4..6。这里的关键点是 startAtstartAfter 都基于有序字段的值而不是根据检索到的最后一个文档进行分页。总体来说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 保证。接下来 sn-p 建立在文档示例和您的代码之上。

// 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)

最后请记住,如果文档数量不多,只查询所有文档可能会更简单,并延迟优化直到它们成为性能问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    相关资源
    最近更新 更多