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
相关产品推荐
相关产品推荐

