Swift 如何从地理查询中获取文档?

Swift 如何从地理查询中获取文档?,swift,google-cloud-firestore,geofire,Swift,Google Cloud Firestore,Geofire,我将此函数用于地理查询。但我不知道如何将查询中的文档添加到数组中。因此,我可以使用Firestore文档中的信息显示一些地图注释。我应该如何改变它 func geoQuery() { // [START fs_geo_query_hashes] // Find cities within 50km of London let center = CLLocationCoordinate2D(latitude: 51.5074, longitu

我将此函数用于地理查询。但我不知道如何将查询中的文档添加到数组中。因此,我可以使用Firestore文档中的信息显示一些地图注释。我应该如何改变它

    func geoQuery() {
        // [START fs_geo_query_hashes]
        // Find cities within 50km of London
        let center = CLLocationCoordinate2D(latitude: 51.5074, longitude: 0.1278)
        let radiusInKilometers: Double = 50

        // Each item in 'bounds' represents a startAt/endAt pair. We have to issue
        // a separate query for each pair. There can be up to 9 pairs of bounds
        // depending on overlap, but in most cases there are 4.
        let queryBounds = GFUtils.queryBounds(forLocation: center,
                                              withRadius: radiusInKilometers)
        let queries = queryBounds.compactMap { (any) -> Query? in
            guard let bound = any as? GFGeoQueryBounds else { return nil }
            return db.collection("cities")
                .order(by: "geohash")
                .start(at: [bound.startValue])
                .end(at: [bound.endValue])
        }

        var matchingDocs = [QueryDocumentSnapshot]()
        // Collect all the query results together into a single list
        func getDocumentsCompletion(snapshot: QuerySnapshot?, error: Error?) -> () {
            guard let documents = snapshot?.documents else {
                print("Unable to fetch snapshot data. \(String(describing: error))")
                return
            }

            for document in documents {
                let lat = document.data()["lat"] as? Double ?? 0
                let lng = document.data()["lng"] as? Double ?? 0
                let coordinates = CLLocation(latitude: lat, longitude: lng)
                let centerPoint = CLLocation(latitude: center.latitude, longitude: center.longitude)

                // We have to filter out a few false positives due to GeoHash accuracy, but
                // most will match
                let distance = GFUtils.distance(from: centerPoint, to: coordinates)
                if distance <= radiusInKilometers {
                    matchingDocs.append(document)
                }
            }
        }

        // After all callbacks have executed, matchingDocs contains the result. Note that this
        // sample does not demonstrate how to wait on all callbacks to complete.
        for query in queries {
            query.getDocuments(completion: getDocumentsCompletion)
        }
        // [END fs_geo_query_hashes]
    }
func地理查询(){
//[启动fs\u geo\u查询\u散列]
//查找距离伦敦50公里以内的城市
设中心=CLLOCATIONCOORDIATE2D(纬度:51.5074,经度:0.1278)
let radiusInKilometers:Double=50
//“bounds”中的每一项都代表一个startAt/endAt对。我们必须发出
//每对的单独查询。最多可以有9对边界
//取决于重叠,但在大多数情况下有4个。
让queryBounds=GFUtils.queryBounds(对于位置:center,
withRadius:半径(公里)
让querys=queryBounds.compactMap{(任意)->Query?在
guard let bound=any as?GFGeoQueryBounds else{return nil}
返回数据库集合(“城市”)
.订单(由“geohash”填写)
.start(位于:[bound.startValue])
.end(位于:[bound.endValue])
}
var matchingDocs=[QueryDocumentSnapshot]()
//将所有查询结果收集到一个列表中
func getDocumentsCompletion(快照:QuerySnapshot?,错误:error?)->(){
guard let documents=snapshot?.其他文档{
打印(“无法获取快照数据。\(字符串(描述:错误)))
返回
}
用于文档中的文档{
将lat=document.data()[“lat”]设为双精度??0
将lng=document.data()[“lng”]设为双精度??0
让坐标=CLLocation(纬度:纬度,经度:lng)
设centerPoint=CLLocation(纬度:center.lation,经度:center.longitude)
//由于GeoHash的准确性,我们必须过滤掉一些误报,但是
//大多数都会匹配
让距离=GFUtils.distance(从:中心点到:坐标)

如果距离这是我在结构中的Pin模型:

struct Pin: Identifiable {
    var id = UUID().uuidString
    var location: MKCoordinateRegion
    var name: String
    var img: String
}
然后我将使用地理查询功能:

func geoQuery() {
        // [START fs_geo_query_hashes]
        // Find cities within 50km of London
        let center = CLLocationCoordinate2D(latitude: 51.5074, longitude: 0.1278)
        let radiusInKilometers: Double = 50

        // Each item in 'bounds' represents a startAt/endAt pair. We have to issue
        // a separate query for each pair. There can be up to 9 pairs of bounds
        // depending on overlap, but in most cases there are 4.
        let queryBounds = GFUtils.queryBounds(forLocation: center,
                                              withRadius: radiusInKilometers)
        let queries = queryBounds.compactMap { (any) -> Query? in
            guard let bound = any as? GFGeoQueryBounds else { return nil }
            return db.collection("cities")
                .order(by: "geohash")
                .start(at: [bound.startValue])
                .end(at: [bound.endValue])
        }

        var matchingDocs = [QueryDocumentSnapshot]()
        // Collect all the query results together into a single list
        func getDocumentsCompletion(snapshot: QuerySnapshot?, error: Error?) -> () {
            guard let documents = snapshot?.documents else {
                print("Unable to fetch snapshot data. \(String(describing: error))")
                return
            }

            for document in documents {
                let lat = document.data()["lat"] as? Double ?? 0
                let lng = document.data()["lng"] as? Double ?? 0
                let name = document.data()["names"] as? String ?? "no name"
                let coordinates = CLLocation(latitude: lat, longitude: lng)
                let centerPoint = CLLocation(latitude: center.latitude, longitude: center.longitude)

                // We have to filter out a few false positives due to GeoHash accuracy, but
                // most will match
                let distance = GFUtils.distance(from: centerPoint, to: coordinates)
                if distance <= radiusInKilometers {
                    matchingDocs.append(document)
                }
            }
        }

        // After all callbacks have executed, matchingDocs contains the result. Note that this
        // sample does not demonstrate how to wait on all callbacks to complete.
        for query in queries {
            query.getDocuments(completion: getDocumentsCompletion)
        }
        // [END fs_geo_query_hashes]
    }
func地理查询(){
//[启动fs\u geo\u查询\u散列]
//查找距离伦敦50公里以内的城市
设中心=CLLOCATIONCOORDIATE2D(纬度:51.5074,经度:0.1278)
let radiusInKilometers:Double=50
//“bounds”中的每一项都代表一个startAt/endAt对。我们必须发出
//每对的单独查询。最多可以有9对边界
//取决于重叠,但在大多数情况下有4个。
让queryBounds=GFUtils.queryBounds(对于位置:center,
withRadius:半径(公里)
让querys=queryBounds.compactMap{(任意)->Query?在
guard let bound=any as?GFGeoQueryBounds else{return nil}
返回数据库集合(“城市”)
.订单(由“geohash”填写)
.start(位于:[bound.startValue])
.end(位于:[bound.endValue])
}
var matchingDocs=[QueryDocumentSnapshot]()
//将所有查询结果收集到一个列表中
func getDocumentsCompletion(快照:QuerySnapshot?,错误:error?)->(){
guard let documents=snapshot?.其他文档{
打印(“无法获取快照数据。\(字符串(描述:错误)))
返回
}
用于文档中的文档{
将lat=document.data()[“lat”]设为双精度??0
将lng=document.data()[“lng”]设为双精度??0
让name=document.data()[“names”]作为字符串??“无名称”
让坐标=CLLocation(纬度:纬度,经度:lng)
设centerPoint=CLLocation(纬度:center.lation,经度:center.longitude)
//由于GeoHash的准确性,我们必须过滤掉一些误报,但是
//大多数都会匹配
让距离=GFUtils.distance(从:中心点到:坐标)

如果距离我不知道文档是如何构造的,也不知道地图是如何配置为显示数据的(例如,注释与区域),但解决此问题的一般方法是协调函数中的查询循环,并为它们提供一个完成处理程序。为此,我们可以使用分派组。在该组的完成处理程序中,您有一个文档快照数组,需要循环通过该数组来获取数据(来自每个文档),构造
Pin
,并将其添加到地图中。此处涉及的许多其他步骤我无法帮助您,因为我不知道您的文档和地图是如何配置的,但这将对您有所帮助。也就是说,您可以稍微减少此代码并使其更高效,但我们还是使用您正在使用的Firebase示例代码吧首先让它工作

struct Pin: Identifiable {
    let id = UUID().uuidString
    var location: MKCoordinateRegion
    var name: String
    var img: String
}

func geoQuery() {
    // [START fs_geo_query_hashes]
    // Find cities within 50km of London
    let center = CLLocationCoordinate2D(latitude: 51.5074, longitude: 0.1278)
    let radiusInKilometers: Double = 50
    
    // Each item in 'bounds' represents a startAt/endAt pair. We have to issue
    // a separate query for each pair. There can be up to 9 pairs of bounds
    // depending on overlap, but in most cases there are 4.
    let queryBounds = GFUtils.queryBounds(forLocation: center,
                                          withRadius: radiusInKilometers)
    let queries = queryBounds.compactMap { (Any) -> Query? in
        guard let bound = Any as? GFGeoQueryBounds else { return nil }
        return db.collection("cities")
            .order(by: "geohash")
            .start(at: [bound.startValue])
            .end(at: [bound.endValue])
    }
    
    // Create a dispatch group outside of the query loop since each iteration of the loop
    // performs an asynchronous task.
    let dispatch = DispatchGroup()
    
    var matchingDocs = [QueryDocumentSnapshot]()
    // Collect all the query results together into a single list
    func getDocumentsCompletion(snapshot: QuerySnapshot?, error: Error?) -> () {
        guard let documents = snapshot?.documents else {
            print("Unable to fetch snapshot data. \(String(describing: error))")
            dispatch.leave() // leave the dispatch group when we exit this completion
            return
        }
        
        for document in documents {
            let lat = document.data()["lat"] as? Double ?? 0
            let lng = document.data()["lng"] as? Double ?? 0
            let name = document.data()["names"] as? String ?? "no name"
            let coordinates = CLLocation(latitude: lat, longitude: lng)
            let centerPoint = CLLocation(latitude: center.latitude, longitude: center.longitude)
            
            // We have to filter out a few false positives due to GeoHash accuracy, but
            // most will match
            let distance = GFUtils.distance(from: centerPoint, to: coordinates)
            if distance <= radiusInKilometers {
                matchingDocs.append(document)
            }
        }
        dispatch.leave() // leave the dispatch group when we exit this completion
    }
    
    // After all callbacks have executed, matchingDocs contains the result. Note that this
    // sample does not demonstrate how to wait on all callbacks to complete.
    for query in queries {
        dispatch.enter() // enter the dispatch group on each iteration
        query.getDocuments(completion: getDocumentsCompletion)
    }
    // [END fs_geo_query_hashes]
    
    // This is the completion handler of the dispatch group. When all of the leave()
    // calls equal the number of enter() calls, this notify function is called.
    dispatch.notify(queue: .main) {
        for doc in matchingDocs {
            let lat = doc.data()["lat"] as? Double ?? 0
            let lng = doc.data()["lng"] as? Double ?? 0
            let name = doc.data()["names"] as? String ?? "no name"
            let coordinates = CLLocation(latitude: lat, longitude: lng)
            let region = MKCoordinateRegion(center: <#T##CLLocationCoordinate2D#>, latitudinalMeters: <#T##CLLocationDistance#>, longitudinalMeters: <#T##CLLocationDistance#>)
            let pin = Pin(location: region, name: name, img: "someImg")
            
            // Add pin to array and then to map or just add pin directly to map here.
        }
    }
}
struct Pin:可识别{
设id=UUID().UUIString
变量位置:MKCoordinateRegion
变量名称:String
var-img:String
}
func geoQuery(){
//[启动fs\u geo\u查询\u散列]
//查找距离伦敦50公里以内的城市
设中心=CLLOCATIONCOORDIATE2D(纬度:51.5074,经度:0.1278)
let radiusInKilometers:Double=50
//“bounds”中的每一项都代表一个startAt/endAt对。我们必须发出
//每对的单独查询。最多可以有9对边界
//取决于重叠,但在大多数情况下有4个。
让queryBounds=GFUtils.queryBounds(对于位置:center,
withRadius:半径(公里)
让querys=queryBounds.compactMap{(任意)->Query?在
guard let bound=Any as?GFGeoQueryBounds else{return nil}
返回数据库集合(“城市”)
.订单(由“geohash”填写)
        Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true, annotationItems: pvm.allPins) { pin in
                MapAnnotation(coordinate: pin.location.coordinate) {
                    Image(pin.img)
                }
                
            }