【问题标题】: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
          相关资源
          最近更新 更多