FireStore 不返回所有结果

Posted

技术标签:

【中文标题】FireStore 不返回所有结果【英文标题】:FireStore not return all results 【发布时间】:2021-06-21 23:11:48 【问题描述】:

我想从 firestore 获取数据,假设我在一个集合中有 10 个文档。之后我必须在每个文档中获取数据,所以我将数据保存在 ArrayList 中。但是 FireBase 永远不会返回集合中的所有文档。有时它只返回包含 10 个文档的集合中的 5 ,6 个文档。

我的 fireBaseUtil :

fun getDocumentByQueryAList( idQuery: List<String>, callBack: (ArrayList<DocumentSnapshot>) -> Unit) 
        val listDocumentSnapshot = ArrayList<DocumentSnapshot>()
        collRef = fireStore.collection("myCollection")
        val size = idQuery.size
        for (i in 0 until size) 
            val query = collRef.whereEqualTo("fieldQuery", idQuery[i])
            query.get().addOnSuccessListener  documents ->
                for (document in documents) 
                    listDocumentSnapshot.add(document)
                    if (i == size - 1) 
                        callBack.invoke(listDocumentSnapshot)
                    
                
            
        
    

我在 size = 10 时注销,但 i = 8 它调用了invoke....

用户存储库:

FireBaseUtil.getDocumentByQueryAList
// myList.addAll(listGettedByCallback)

->> 当我想在我的列表中有数据时,我调用 FireBaseUtil.getDocumentByQueryAList。我知道firebase异步返回值,但我不知道如何获取我的所有文档然后receiver.invoke(“callbackValue”)。 请告诉我有什么解决办法。提前致谢。

【问题讨论】:

【参考方案1】:

您遇到的问题是您希望查询按如下顺序运行:

get idQuery[0], then add to list, then
get idQuery[1], then add to list, then
get idQuery[2], then add to list, then
...
get idQuery[8], then add to list, then
get idQuery[9], then add to list, then
invoke callback

但实际上,以下所有事情都是同时发生的。

get idQuery[0] (add to list when finished)
get idQuery[1] (add to list when finished)
get idQuery[2] (add to list when finished)
...
get idQuery[8] (add to list when finished)
get idQuery[9] (add to list and invoke callback when finished)

如果get idQuery[9] 在其他一些之前完成,您将在列表完全填满之前调用您的回调。

解决此问题的一种原始方法是计算完成的 get 查询的数量,当所有查询都完成时,调用回调。

fun getDocumentByQueryAList( idQuery: List<String>, callBack: (ArrayList<DocumentSnapshot>) -> Unit) 
  val listDocumentSnapshot = ArrayList<DocumentSnapshot>()
  collRef = fireStore.collection("myCollection")
  val size = idQuery.size
  val finishedCount = 0
  for (i in 0 until size) 
    val query = collRef.whereEqualTo("fieldQuery", idQuery[i])
    query.get().addOnSuccessListener  documents ->
      for (document in documents) 
        listDocumentSnapshot.add(document)
      
      
      if (++finishedCount == size)  // ++finishedCount will add 1 to finishedCount, and return the new value
        // all tasks done
        callBack.invoke(listDocumentSnapshot)
      
    
  

但是,如果任何查询失败,这将遇到永远不会调用回调的问题。您可以使用addOnFailureListeneraddOnCompleteListener 来处理这些失败的任务。

更正确和正确的方法是使用Tasks.whenAll,它的使用方式与使用Promise.all 查看javascript 答案的方式类似。我自己还是 Kotlin 语法的新手,所以预计以下代码块可能会引发错误。

fun getDocumentByQueryAList( idQueryList: List<String>, callBack: (ArrayList<DocumentSnapshot>) -> Unit) 
  val listDocumentSnapshot = ArrayList<DocumentSnapshot>()
  collRef = fireStore.collection("myCollection")
  val getTasks = new ArrayList<Task<Void>>();
  for (idQuery in idQueryList) 
    val query = collRef.whereEqualTo("fieldQuery", idQuery)
    getTasks.add(
      query.get()
        .onSuccessTask  documents ->
          // if query succeeds, add matching documents to list
          for (document in documents) 
            listDocumentSnapshot.add(document)
          
        
    )
  
  
  Tasks.whenAll(getTasks)
    .addOnSuccessListener  results -> 
      callback.invoke(listDocumentSnapshot)
    
    .addOnFailureListener  errors -> 
      // one or more get queries failed
      // do something
    

您可以不使用回调,而是返回一个 Task,最后一位是:

return Tasks.whenAll(getTasks)
  .onSuccessTask  results ->
    return listDocumentSnapshot
  

这将允许您将以下内容与其他 TaskTasks 方法一起使用。

getDocumentByQueryAList(idQueryList)
  .addOnSuccessListener  /* ... */ 
  .addOnFailureListener  /* ... */ 

【讨论】:

@HoanCong 如果这解决了你的问题,别忘了mark it as the accepted answer。【参考方案2】:

使用 RxJava 像这样使用 smth:

override fun getAllDocs(): Single<List<MyClass>> 
    return Single.create  emitter ->
        db.collection("myCollection").get()
                .addOnSuccessListener  documents ->
                    val list = mutableListOf<MyClass>()
                    documents.forEach  document -> 
                        list.add(mapDocumentToMyClass(document))
                    emitter.onSuccess(list)
                
                .addOnFailureListener  exception ->
                    emitter.onError(exception)
                
    


private fun mapDocumentToMyClass(documentSnapshot: QueryDocumentSnapshot) =
        MyClass(
                documentSnapshot.get(ID).toString(),
                documentSnapshot.get(SMTH).toString(),
                // some extra fields
                null
        )

或者像这样使用协程:

override suspend fun getAllDocs(): List<MyClass> 
    return try 
        val snapshot =
            db.collection("myCollection")
                .get()
                .await()
        snapshot.map 
            mapDocumentToMyClass(it)
        
     catch (e: Exception) 
        throw e
    

此功能可帮助您从一个文档中获取所有数据

【讨论】:

以上是关于FireStore 不返回所有结果的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Firestore 有时不返回任何内容,没有错误,啥也没有?

如何从 firestore 两个集合中获取数据并将所有数据合并在一起

使用python在Firestore中运行GeoPoint

Firebase Firestore 不返回文档

SwiftUI + Firestore - 基于从 Firestore 返回的数组的过滤器列表

作为 Kotlin 中的函数的结果,如何从 Firestore 数据库返回列表?