You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore GeoHash查询返回空结果及回调不执行问题排查

Firestore GeoHash范围查询结果为空问题排查

回调函数逻辑说明

getDocumentsCompletion 是 query.getDocuments 方法的异步完成回调,不需要手动传入参数调用。当单次Firestore查询执行完成(无论成功返回结果还是请求报错),Firebase SDK会自动将查询快照、错误信息作为入参传入,执行函数内的逻辑。
你在for循环内添加的打印能正常输出,仅代表你成功遍历了所有查询条件、调用了4次查询发起方法,不代表查询已经执行完成、回调已经触发。

回调不触发、结果为空的核心原因

回调完全不执行,本质是异步查询还没等到返回结果,当前代码的执行上下文就被释放了。最常见的场景是你把这段查询逻辑写在临时作用域里,for循环执行完就立刻退出当前函数/作用域,没有给异步请求留执行时间,此时直接读取matchingDocs当然是空数组。
另外如果Firestore安全规则配置错误、拒绝了查询请求,回调会走到error分支,如果你没加错误分支的打印,也会表现为“回调没执行”。

修复方法

用DispatchGroup管理所有异步查询,等所有查询的回调都执行完成后,再处理匹配结果,修改后的核心逻辑如下:

// Find cities within 50km of London
let center = CLLocationCoordinate2D(latitude: 51.5074, longitude: 0.1278)
let radiusInM: Double = 50 * 1000

// 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: radiusInM)
let queries = queryBounds.map { bound -> Query in
    return db.collection("cities")
        .order(by: "geohash")
        .start(at: [bound.startValue])
        .end(at: [bound.endValue])
}

// 用调度组管理多个异步查询
let queryGroup = DispatchGroup()
var matchingDocs = [QueryDocumentSnapshot]()

// Collect all the query results together into a single list
func getDocumentsCompletion(snapshot: QuerySnapshot?, error: Error?) -> () {
    // 函数退出前标记当前查询完成
    defer { queryGroup.leave() }
    
    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 <= radiusInM {
            matchingDocs.append(document)
        }
    }
}

for query in queries {
    // 发起查询前标记待完成任务数+1
    queryGroup.enter()
    query.getDocuments(completion: getDocumentsCompletion)
}

// 所有查询回调执行完成后触发
queryGroup.notify(queue: .main) {
    // 所有结果处理逻辑必须写在这里,此时matchingDocs才是完整的匹配结果
    print("匹配到的文档总数: \(matchingDocs.count)")
}

额外排查点

如果修改后还是拿不到结果,依次检查以下配置:

  • Firestore安全规则是否允许当前登录用户读取cities集合
  • 集合内文档的geohash、lat、lng字段是否都是数字类型,不要存成字符串
  • 存储的GeoHash值和经纬度是否匹配,不要出现经纬度和GeoHash对应不上的情况

内容的提问来源于stack exchange,提问作者user19498841

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 00:57:20