Android Firestore 查询分页 FirebaseFirestoreException: INVALID_ARGUMENT
Android Firestore query paging FirebaseFirestoreException: INVALID_ARGUMENT
我有一个函数可以从我的 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 文档结构
如果我们稍微简化您的代码,您正在做:
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()
因此,您通过在其上再次调用 whereEqualTo
和 orderBy
,从其原始值构建 data
,这是错误消息抱怨什么。
最简单的解决方法是不重复使用数据的现有值,因此将 data = data.query
更改为 data = dbRef.collection("posts")
。
但您似乎在尝试构建器模式,这实际上是一种更好的方法。在这种情况下,您需要确保您没有重建整个查询,而只是添加与分页部分相关的子句:
data = data.query
.startAfter(lastVisible)
.get()
.await()
所以这里我们只是添加 startAfter
子句,因为所有其他条件在您首次构建它时已经存在于 data.query
中。
我有一个函数可以从我的 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 文档结构
如果我们稍微简化您的代码,您正在做:
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()
因此,您通过在其上再次调用 whereEqualTo
和 orderBy
,从其原始值构建 data
,这是错误消息抱怨什么。
最简单的解决方法是不重复使用数据的现有值,因此将 data = data.query
更改为 data = dbRef.collection("posts")
。
但您似乎在尝试构建器模式,这实际上是一种更好的方法。在这种情况下,您需要确保您没有重建整个查询,而只是添加与分页部分相关的子句:
data = data.query
.startAfter(lastVisible)
.get()
.await()
所以这里我们只是添加 startAfter
子句,因为所有其他条件在您首次构建它时已经存在于 data.query
中。