简体   繁体   English

SwiftUI 中具有实时更新结果的 Firestore Geohash 查询

[英]Firestore Geohash Query with Live Updating Results in SwiftUI

I'm trying to build an iOS app in SwiftUI where users can find a "Post" near to their current location.我正在尝试在 SwiftUI 中构建一个 iOS 应用程序,用户可以在其中找到靠近其当前位置的“帖子”。 I have a sub collection called Posts with a geohash.我有一个名为 Posts 的子集合,带有 geohash。 Somewhat annoyingly this library by google has been archived https://github.com/firebase/geofire-objc for no reason.有点烦人的是,谷歌的这个库已无缘无故地存档https://github.com/firebase/geofire-objc Instead I had to use this library https://github.com/emilioschepis/swift-geohash .相反,我不得不使用这个库https://github.com/emilioschepis/swift-geohash

I find all the neighboring geohashes around the current user and then run a query against firstore for each geohash starting with geohash and ending with geohash + '~'.我找到当前用户周围的所有相邻 geohashes,然后针对每个以 geohash 开头并以 geohash + '~' 结尾的 geohash 运行针对 firstore 的查询。 Here is the function I wrote:这是我写的 function:

// import https://github.com/emilioschepis/swift-geohash

class FirestorePosts: ObservableObject {
    
    @Published var items = [FirestorePost]() // Reference to our Model
      
    func geoPointQuery(tag:String){
        do {
            let db = Firestore.firestore().collection("tags")
            let docRef = db.document(tag).collection("posts")
            // users current location is "gcpu"
            let neighbors = try Geohash.neighbors(of: "gcpu", includingCenter: true)
            let queries = neighbors.map { bound -> Query in
                let end = "\(bound)~"
                return docRef
                    .order(by: "geohash")
                    .start(at: [bound])
                    .end(at: [end])
            }
            
            func getDocumentsCompletion(snapshot: QuerySnapshot?, error: Error?) -> () {
                guard let documents = snapshot?.documents else {
                    print("Unable to fetch snapshot data. \(String(describing: error))")
                    return
                }

                self.items += documents.compactMap { queryDocumentSnapshot -> FirestorePost? in
                    return try? queryDocumentSnapshot.data(as: FirestorePost.self)
                }
            }

            for query in queries {
                print("ran geo query")
                query.getDocuments(completion: getDocumentsCompletion)
            }
        }
        catch{
            print(error.localizedDescription)
        }
    }
}

So far the query works and returns items as expected.到目前为止,查询有效并按预期返回项目。 However, the results are not updated in realtime when there is a change in Firestore.但是,当 Firestore 发生变化时,结果不会实时更新。

  1. How could I make this query update results in realtime?我怎样才能使这个查询实时更新结果? I tried adding query.addSnapshotListener instead but it doesn't like "completion:" parameter我尝试添加query.addSnapshotListener ,但它不喜欢“完成:”参数
  2. How can I ensure that all the queries are finished before returning the results如何确保在返回结果之前完成所有查询

You're calling query.getDocuments , which gets data once .您正在调用query.getDocuments ,它 获取数据一次 If you want to also get updates to that data, you should use addSnapshotListener which listens for updates after getting the initial docs.如果您还想获取该数据的更新,您应该使用addSnapshotListener ,它会在获取初始文档后侦听更新

To ensure all queries are finished, you could keep a simple counter that you increase each time your addSnapshotListener callback is invoked.为确保所有查询都已完成,您可以保留一个简单的计数器,每次调用addSnapshotListener回调时都会增加该计数器。 When the counter is equal to the number of queries, all of them have gotten a response from the server.当计数器等于查询次数时,所有的查询都得到了服务器的响应。 That's exactly what the geofire-* libraries for Realtime Database do for their onReady event.这正是实时数据库的geofire-*库为其onReady事件所做的。

I refactored to this and it seems to work and updates in realtime.我对此进行了重构,它似乎可以实时工作和更新。 I didn't need to use a counter since Im appending the documents to self.items (not sure if thats correct though).我不需要使用计数器,因为我将文档附加到self.items (虽然不确定那是否正确)。

...
for query in queries {
    query.addSnapshotListener { (querySnapshot, error) in
        guard let documents = querySnapshot?.documents else {
            print("No documents")
            return
        }
        
        self.items += documents.compactMap { queryDocumentSnapshot -> FirestorePost? in
            return try? queryDocumentSnapshot.data(as: FirestorePost.self)
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM