【问题标题】:Android Firestore query paging FirebaseFirestoreException: INVALID_ARGUMENTAndroid Firestore 查询分页 FirebaseFirestoreException: INVALID_ARGUMENT
【发布时间】:2021-06-03 09:34:31
【问题描述】:

我有一个从我的 firestore 数据库中获取帖子的函数,我正在关注文档以按最后一个索引文档分页查询,但由于某种原因,在尝试运行下一个查询时第一次获取后,我收到 com.google.firebase.firestore.FirebaseFirestoreException: INVALID_ARGUMENT: Order by clause cannot contain duplicate fields uploadTimeStamp

我还登录并看到查询似乎没问题,lastVisible 在运行第一个查询后实际上是文档列表中的索引 4,但不知何故在第二个查询中我再次收到所有前 5 个帖子..

知道我做错了什么吗?


suspend fun getMyPosts(userID: String): Flow<MutableList<DocumentSnapshot>> = flow {
        Log.d(TAG, "getMyPosts() called -> userID is $userID")
        var data: QuerySnapshot? = null
        try {
            data = dbRef.collection("posts")
                .whereEqualTo("userID", userID)
                .orderBy("uploadTimeStamp", Query.Direction.DESCENDING)
                .limit(5)
                .get()
                .await()
            Log.d(TAG, "emitting ${data.documents.size} posts: \n")
            data.documents.forEach { doc ->
                Log.d(
                    TAG,
                    "post number ${data.documents.indexOf(doc)}, timestamp: ${doc.get("uploadTimeStamp")}"
                )
            }

            emit(data.documents)
            while (!data!!.isEmpty && data.size() == 5) {
                Log.d(TAG, "getting more posts")
                val lastVisible = data.documents[data.size() - 1]
                Log.d(TAG, "last index is ${data.size() - 1}")
                Log.d(TAG, "lastVisible is ${lastVisible.get("uploadTimeStamp")}")
                data = data.query
                    .whereEqualTo("userID", userID)
                    .orderBy("uploadTimeStamp", Query.Direction.DESCENDING)
                    .startAfter(lastVisible)
                    .limit(5)
                    .get()
                    .await()
                if (!data.isEmpty) {
                    Log.d(TAG, "emitting ${data.documents}")
                    emit(data.documents)
                }
            }
        } catch (e: Exception) {
            Log.d(TAG, "Failed to get MyPosts,\n $e")
            data!!.documents.forEach { doc ->
                Log.d(
                    TAG,
                    "post number ${data.documents.indexOf(doc)}, timestamp: ${doc.get("uploadTimeStamp")}"
                )
            }
        }
    }

这是我运行 getMyPosts() 时的 logcat,所以你可以看到我以某种方式再次获得了前 5 个文档:


2021-06-03 12:31:33.349 4990-5249/avedot.app D/AppRepository: getMyPosts() called -> userID is ncTe77npPHPJyQvJJdRUAY1fEBB3
2021-06-03 12:31:34.048 4990-5249/avedot.app D/AppRepository: emitting 5 posts: 
2021-06-03 12:31:34.048 4990-5249/avedot.app D/AppRepository: post number 0, timestamp: 1622708658810
2021-06-03 12:31:34.048 4990-5249/avedot.app D/AppRepository: post number 1, timestamp: 1622708316148
2021-06-03 12:31:34.049 4990-5249/avedot.app D/AppRepository: post number 2, timestamp: 1622665878322
2021-06-03 12:31:34.049 4990-5249/avedot.app D/AppRepository: post number 3, timestamp: 1622665769466
2021-06-03 12:31:34.049 4990-5249/avedot.app D/AppRepository: post number 4, timestamp: 1622661053130
2021-06-03 12:31:34.082 4990-5249/avedot.app D/AppRepository: getImages() called
2021-06-03 12:31:34.083 4990-5249/avedot.app D/AppRepository: [false, false, true]
2021-06-03 12:31:35.345 4990-5249/avedot.app D/AppRepository: [false, true, true]
2021-06-03 12:31:36.068 4990-5249/avedot.app D/AppRepository: [true, true, true]
2021-06-03 12:31:37.084 4990-5249/avedot.app D/AppRepository: [false, false, true]
2021-06-03 12:31:37.294 4990-5249/avedot.app D/AppRepository: [false, false, true]
2021-06-03 12:31:37.500 4990-5249/avedot.app D/AppRepository: getting more posts
2021-06-03 12:31:37.500 4990-5249/avedot.app D/AppRepository: last index is 4
2021-06-03 12:31:37.501 4990-5249/avedot.app D/AppRepository: lastVisible is 1622661053130
2021-06-03 12:31:37.666 4990-5249/avedot.app D/AppRepository: Failed to get MyPosts,
     com.google.firebase.firestore.FirebaseFirestoreException: INVALID_ARGUMENT: Order by clause cannot contain duplicate fields uploadTimeStamp
2021-06-03 12:31:37.666 4990-5249/avedot.app D/AppRepository: post number 0, timestamp: 1622708658810
2021-06-03 12:31:37.666 4990-5249/avedot.app D/AppRepository: post number 1, timestamp: 1622708316148
2021-06-03 12:31:37.667 4990-5249/avedot.app D/AppRepository: post number 2, timestamp: 1622665878322
2021-06-03 12:31:37.667 4990-5249/avedot.app D/AppRepository: post number 3, timestamp: 1622665769466
2021-06-03 12:31:37.667 4990-5249/avedot.app D/AppRepository: post number 4, timestamp: 1622661053130

这是我的 Firestore 文档结构

【问题讨论】:

  • 请编辑您的问题并将您的数据库结构添加为屏幕截图。

标签: android firebase kotlin google-cloud-firestore paging


【解决方案1】:

如果我们稍微简化一下你的代码,你就在做:

var data: QuerySnapshot? = null
try {
    data = dbRef.collection("posts")
        .whereEqualTo("userID", userID)
        .orderBy("uploadTimeStamp", Query.Direction.DESCENDING)
        .limit(5)
        .get()
        .await()
    ...
    while (!data!!.isEmpty && data.size() == 5) {
        val lastVisible = data.documents[data.size() - 1]
        data = data.query
            .whereEqualTo("userID", userID)
            .orderBy("uploadTimeStamp", Query.Direction.DESCENDING)
            .startAfter(lastVisible)
            .limit(5)
            .get()
            .await()

因此,您通过在其上调用whereEqualToorderBy 再次,从其原始值构建data,这就是错误消息所抱怨的内容。

最简单的解决方法是不重复使用数据的现有值,因此将data = data.query 更改为data = dbRef.collection("posts")

但是您似乎正在尝试构建器模式,这实际上是一种更好的方法。在这种情况下,您需要确保您没有重建整个查询,而只添加与分页部分相关的子句:

data = data.query
    .startAfter(lastVisible)
    .get()
    .await()

所以这里我们只是添加了startAfter 子句,因为所有其他条件在您第一次构建时已经存在于data.query 中。

【讨论】:

  • 感谢您为我标记它,这真的很有帮助!。事实上,我的循环查询从第一个查询中保存了 orderByWhereEqualTo,因此它指出为重复,所以现在一切正常
  • 很高兴听到。我确实希望再做一个data.query.startAfter(lastVisible) 会带来问题。我通常保留对“基本查询”的引用,即“除startAt/startAfter 之外的所有内容”,以便我可以将其用作分页的基础。
猜你喜欢
  • 1970-01-01
  • 2021-09-11
  • 2021-08-17
  • 2019-11-14
  • 1970-01-01
  • 2018-06-05
  • 2020-08-25
  • 1970-01-01
  • 2018-03-28
相关资源
最近更新 更多