My code is setting geohashes on venues saved to Firebase Firestore as follows:
static func generateGeoHash(latitude: Double, longitude: Double) -> String {
let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
return GFUtils.geoHash(forLocation: location)
}
These are being saving in Firestore as expected: geoHash "gcpvhfh0cv"
For querying the database to get back the venues in the current region, I've followed guidance from the Firestore docs and this thread for implementing the callback competion: How to get Documents out of an geo query?
The resulting function is:
func queryVenuesForRegion(userRegion: MKCoordinateRegion, completion: @escaping ([Venue]) -> Void) {
//Get a reference to the database
let db = Firestore.firestore()
let centerCoordinate = userRegion.center
let radiusInMeters: Double = 50 * 1000 //max(userRegion.span.latitudeDelta, userRegion.span.longitudeDelta) * 5000 // Approximate conversion, adjust as needed
// Calculate the query bounds using GeoFire utility function
let queryBounds = GFUtils.queryBounds(forLocation: centerCoordinate, withRadius: radiusInMeters)
// Create a query to retrieve venues within the region
let queries = queryBounds.map { bound -> Query in
return db.collection("venues")
.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 in a sinlge list
func getDocumentsCompletion(snapshot: QuerySnapshot?, error: Error?) {
guard let documents = snapshot?.documents else {
print("Unable to fetch snapshot data. \(String(describing: error))")
completion([])
dispatch.leave() // leave the dispatch group when we exit this completion
return
}
for document in documents {
let lat = document.data()["latitute"] as? Double ?? 0
let lng = document.data()["longitude"] as? Double ?? 0
let coordinates = CLLocation(latitude: lat, longitude: lng)
let centerPoint = CLLocation(latitude: centerCoordinate.latitude, longitude: centerCoordinate.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 <= radiusInMeters {
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]
var venues = [Venue]()
dispatch.notify(queue: .main) {
for document in matchingDocs {
if let venue = try? document.data(as: Venue.self) {
venues.append(venue)
}
}
}
// Call the completion handler with the parsed venues
completion(venues)
}
The code is being called and the regions line up (long and lat both for eg central london).
queryBounds and queries have data, but documents and matchingDocs always remain empty.
Retrieving all docs from the database successes and map annotation as applied.
Trying to debug for ages but with no luck. Driving me bonkers. Any ideas welcome.