【问题标题】:Get several ids documents firestore获取几个ids文件firestore
【发布时间】:2019-09-11 18:23:06
【问题描述】:

如何从 firestore 获取 ids 文档

现在我从 backend 获得了几个 ids 文档,我需要在 tableview 中显示收到的 ids 文档。

firestore 我有这个 ids

xNlguCptKllobZ9XD5m1 uKDbeWxn9llz52WbWj37 82s6W3so0RAKPZFzGyl6 EF6jhVgDr52MhOILAAwf FXtsMKOTvlVhJjVCBFj8 JtThFuT4qoK4TWJGtr3n TL1fOBgIlX5C7qcSShGu UkZq3Uul5etclKepRjJF aGzLEsEGjNA9nwc4VudD dZp0qITGVlYUCFw0dS8C n0zizZzw7WTLpXxcZNC6

例如,我的 backend 只找到了这个 ids

JtThFuT4qoK4TWJGtr3n TL1fOBgIlX5C7qcSShGu UkZq3Uul5etclKepRjJF

aGzLEsEGjNA9nwc4VudD dZp0qITGVlYUCFw0dS8C n0zizZzw7WTLpXxcZNC6

我只需要在 tableview 中显示这三个 id。 (但实际上后端返回了 100 多个 id,在下面你可以看到对这些 id 进行疯狂排序)

Backend 将此 id 附加到临时数组 var tempIds: [String] = []

那么我如何才能从 firestore 只获取这些 id 并在 tableview 中显示它们?

我使用这个代码:

fileprivate func query(ids: String) {
    Firestore.firestore().collection(...).document(ids).getDocument{ (document, error) in
        if let doc = document, doc.exists {
            if let newModel = Halls(dictionary: doc.data()!, id: doc.documentID) {
                self.halls.append(newModel)
                self.halls.shuffle()
                self.halls.sort(by: { $0.priority > $1.priority })
                self.tableView.reloadData()
            } else {
                fatalError("Fatal error")
            }
        } else {
            return
        }
    }
}

我需要在后台处理来自 backend 的 id,并且在处理之后需要在 tableview 中显示处理后的 id,而不需要进行疯狂的排序。

可能需要使用addSnapshotListened,但我不明白如何。

更新代码:

for id in idsList {
                            dispatchGroup.enter()
                            Firestore.firestore().collection(...).document(id).getDocument{ (document, error) in
                                if let doc = document, doc.exists {
                                    if let newHallModel = Halls(dictionary: doc.data()!, id: doc.documentID) {
                                        self.tempHalls.append(newHallModel)
                                        dispatchGroup.leave()
                                    } else {
                                        fatalError("Fatal error")
                                    }
                                } else {
                                    print("Document does not exist")
                                    MBProgressHUD.hide(for: self.view, animated: true)
                                    return
                                }
                            }
                        }

                        dispatchGroup.notify(queue: .global(qos: .default), execute: {

                            self.halls = self.tempHalls

                            DispatchQueue.main.async {
                                MBProgressHUD.hide(for: self.view, animated: true)
                                self.tableView.reloadData()
                            }
                        })

【问题讨论】:

    标签: ios swift firebase google-cloud-firestore document


    【解决方案1】:

    当您需要单个文档或无法(基于您的数据架构)查询的文档时,应使用通过其标识符获取文档。不要犹豫对数据进行非规范化以使查询工作,这就是 NoSQL 的重点。如果我是你,我要么在这些文档中添加一个可以查询的字段,要么用一个新的集合来非规范化这个数据集(仅用于这个查询)。但是,如果您仍然选择通过标识符获取多个文档,那么您需要发出 n getDocument 请求并使用调度组来处理异步:

    let docIds = ["JtThFuT4qoK4TWJGtr3n", "TL1fOBgIlX5C7qcSShGu", "UkZq3Uul5etclKepRjJF"]
    
    let d = DispatchGroup()
    
    for id in docIds {
        
        d.enter()
        
        Firestore.firestore().collection(...).document(id).getDocument{ (document, error) in
            
            // append to array
            d.leave()
    
        }
        
    }
    
    d.notify(queue: .global(), execute: {
        
        // hand off to another array if this table is ever refreshed on the fly
        
        DispatchQueue.main.async {
            // reload table
        }
        
    })
    

    调度组所做的只是记录它进入和离开的次数,当它们匹配时,它调用它的notify(queue:execute:) 方法(它的完成处理程序)。

    【讨论】:

    • 我更新了代码。如果我的数据少于 10 个元素,一切正常,但如果我的数据有 100 多个元素,应用程序崩溃
    • 您必须在每次数据库返回时离开调度组。在您的代码中,您只会在成功读取数据时离开该组,因此请更新它。但同样,您为什么不为此执行查询而不是单独获取文档?
    • 怎么办?你在说什么
    • 关于离开组我修复它并且它工作,谢谢
    【解决方案2】:

    而不是一个接一个地获取文档, 您可以使用“IN”查询通过 1 个请求获取 10 个文档:

    userCollection.where('uid', 'in', ["1231","222","2131"]);
    // or 
    myCollection.where(firestore.FieldPath.documentId(), 'in', ["123","456","789"]);
    

    Firestore 文档: “使用 in 运算符将同一字段上的最多 10 个相等 (==) 子句与逻辑 OR 组合在一起。in 查询返回给定字段与任何比较值匹配的文档”

    【讨论】:

      【解决方案3】:

      我也面临同样的任务。并且没有更好的解决方案。一个一个地获取文档,所以我写了一个小扩展:

      extension CollectionReference {
      typealias MultiDocumentFetchCompletion = ([String: Result<[String: Any], Error>]) -> Void
      
      class func fetchDocuments(with ids: [String], in collection: CollectionReference, completion:@escaping MultiDocumentFetchCompletion) -> Bool  {
          guard ids.count > 0, ids.count <= 50 else { return false }
          var results = [String: Result<[String: Any], Error>]()
          for documentId in ids {
              collection.document(documentId).getDocument(completion: { (documentSnapshot, error) in
                  if let documentData = documentSnapshot?.data() {
                      results[documentId] = .success(documentData)
                  } else {
                      results[documentId] = .failure(NSError(domain: "FIRCollectionReference", code: 0, userInfo: nil))
                  }
                  if results.count == ids.count {
                      completion(results)
                  }
              })
          }
          return true
      }
      }
      

      【讨论】:

        【解决方案4】:

        Swift5 和组合:

        func getRegisteredUsers(usersId: [String]) -> AnyPublisher<[RegisteredUser], Error> {
            return Future<[RegisteredUser], Error> { promise in
                self.db.collection("registeredUsers")
                    .whereField(FieldPath.documentID(), in: usersId)
                    .getDocuments { snapshot, error in
                        
                        do {
                            let regUsers = try snapshot?.documents.compactMap {
                                try $0.data(as: RegisteredUser.self)
                            }
                            
                            promise(.success(regUsers ?? []))
                        } catch {
                            promise(.failure(.default(description: error.localizedDescription)))
                        }
                    
                }
            }
            .eraseToAnyPublisher()
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多