如何检索按字段值排序的文档索引?
How to retireve a document index ranked by field value?
在我的 Android 测验应用程序中,我使用 Firebase Firestore 和 Pagination v3 Android Jetpack 库实现了排行榜,每个页面包含 2 个元素以降低阅读成本。我通过名为“分数”的字段的降序值查询文档。它适用于排行榜顶部的人。但是当用户例如第 1000 个时,如果不查询 1000 个文档我就无法显示它,因此它将花费 1000 次读取。那么有没有一种不用查询所有文档就能得到用户排名的方法呢?
编辑:
@HiltViewModel
class LeaderboardScreenViewModel @Inject constructor(
) : ViewModel() {
private val db = Firebase.firestore
val loadingState = MutableStateFlow(LoadingState.IDLE)
val flow = Pager(PagingConfig(pageSize = 2)) {
FirestorePagingSource(
queryBestScores = db.collection("users_public_details").orderBy("score", Query.Direction.DESCENDING)
.limit(6L)
)
}.flow
.cachedIn(viewModelScope)
}
class FirestorePagingSource(
private val queryBestScores: Query
) : PagingSource<QuerySnapshot, DocumentSnapshot>() {
override fun getRefreshKey(state: PagingState<QuerySnapshot, DocumentSnapshot>): QuerySnapshot? =
null
override suspend fun load(params: LoadParams<QuerySnapshot>): LoadResult<QuerySnapshot, DocumentSnapshot> {
return try {
val currentPage = params.key ?: queryBestScores.get().await()
val lastVisibleScore = currentPage.documents[currentPage.size() - 1]
val nextPage = queryBestScores.startAfter(lastVisibleScore).get().await()
LoadResult.Page(
data = currentPage.documents,
prevKey = null,
nextKey = nextPage
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
Is there a way to filter documents by a field value and get the 1000th of them without querying the previous 999 documents?
这实际上是不可能的。对于 Firestore,您只能使用 Query#limit(long limit) 方法请求特定大小的数据页面。话虽如此,您可以从查询的开头开始,并逐个获取相同大小的后续页面。此操作应继续执行其他类似操作,直到到达包含第 1000 个文档的页面。
您无法直接跳转到该文档。你总是必须阅读所有前面的页面。因此,您必须从第一页开始,然后使用 query cursors 向前浏览页面,方法是指定哪个文档是上一个查询中的最后一个文档。
除此之外,由于 Firestore 中的集合不维护文档计数,除非您创建和维护自己的文档计数,否则您将无法提前知道有多少页数据。
如果您想实现一种处理分页的现代方式,您应该考虑实现 so-called“无限滚动”。 Facebook 做到了这一点,Instagram 做到了这一点。那里有很多例子。
我也写过一篇文章叫:
我在其中解释了如何计算 Firestore 集合中的文档。
在我的 Android 测验应用程序中,我使用 Firebase Firestore 和 Pagination v3 Android Jetpack 库实现了排行榜,每个页面包含 2 个元素以降低阅读成本。我通过名为“分数”的字段的降序值查询文档。它适用于排行榜顶部的人。但是当用户例如第 1000 个时,如果不查询 1000 个文档我就无法显示它,因此它将花费 1000 次读取。那么有没有一种不用查询所有文档就能得到用户排名的方法呢?
编辑:
@HiltViewModel
class LeaderboardScreenViewModel @Inject constructor(
) : ViewModel() {
private val db = Firebase.firestore
val loadingState = MutableStateFlow(LoadingState.IDLE)
val flow = Pager(PagingConfig(pageSize = 2)) {
FirestorePagingSource(
queryBestScores = db.collection("users_public_details").orderBy("score", Query.Direction.DESCENDING)
.limit(6L)
)
}.flow
.cachedIn(viewModelScope)
}
class FirestorePagingSource(
private val queryBestScores: Query
) : PagingSource<QuerySnapshot, DocumentSnapshot>() {
override fun getRefreshKey(state: PagingState<QuerySnapshot, DocumentSnapshot>): QuerySnapshot? =
null
override suspend fun load(params: LoadParams<QuerySnapshot>): LoadResult<QuerySnapshot, DocumentSnapshot> {
return try {
val currentPage = params.key ?: queryBestScores.get().await()
val lastVisibleScore = currentPage.documents[currentPage.size() - 1]
val nextPage = queryBestScores.startAfter(lastVisibleScore).get().await()
LoadResult.Page(
data = currentPage.documents,
prevKey = null,
nextKey = nextPage
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
Is there a way to filter documents by a field value and get the 1000th of them without querying the previous 999 documents?
这实际上是不可能的。对于 Firestore,您只能使用 Query#limit(long limit) 方法请求特定大小的数据页面。话虽如此,您可以从查询的开头开始,并逐个获取相同大小的后续页面。此操作应继续执行其他类似操作,直到到达包含第 1000 个文档的页面。
您无法直接跳转到该文档。你总是必须阅读所有前面的页面。因此,您必须从第一页开始,然后使用 query cursors 向前浏览页面,方法是指定哪个文档是上一个查询中的最后一个文档。
除此之外,由于 Firestore 中的集合不维护文档计数,除非您创建和维护自己的文档计数,否则您将无法提前知道有多少页数据。
如果您想实现一种处理分页的现代方式,您应该考虑实现 so-called“无限滚动”。 Facebook 做到了这一点,Instagram 做到了这一点。那里有很多例子。
我也写过一篇文章叫:
我在其中解释了如何计算 Firestore 集合中的文档。