I need to fetch all users within x radius that match the preferences of the current user.
So I started implementing geohash from Firebase, the documentation was great, my problem might be silly but I don't know when to use all my compound queries...(whereField) I'm specifying them in the "for query in queries" below but I have the feeling It's not the right spot. how do you use compound queries when using geohash?
//MARK: - GET MATCHES WITH GEOHASH
func getMatchesNearMe(radius: Double) {
// Find matches within 50km of my location
let user = UserService.shared.user
let center = CLLocationCoordinate2D(latitude: user.latitude ?? 0, longitude: user.longitude ?? 0)
let radiusInKilometers: Double = radius
// 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("users")
.order(by: "geohash")
.start(at: [bound.startValue])
.end(at: [bound.endValue])
}
var matchingDocs = [Matches]()
// 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
}
print("\nDocs: Count \(documents.count)")
for doc in snapshot!.documents {
var m = Matches()
m.latitude = doc.data()["latitude"] as? Double ?? 0
m.longitude = doc.data()["longitude"] as? Double ?? 0
let coordinates = CLLocation(latitude: m.latitude ?? 0, longitude: m.longitude ?? 0)
let centerPoint = CLLocation(latitude: center.latitude, longitude: center.longitude)
m.id = doc.data()["id"] as? String ?? ""
m.name = doc.data()["name"] as? String ?? ""
m.birthdate = doc.data()["birthdate"] as? Date ?? Date()
m.gender = doc.data()["gender"] as? String ?? ""
m.datingPreferences = doc.data()["datingPreferences"] as? String ?? ""
m.height = doc.data()["height"] as? Int ?? 0
m.imageUrl1 = doc.data()["photo1"] as? String ?? ""
m.imageUrl2 = doc.data()["photo2"] as? String ?? ""
m.imageUrl3 = doc.data()["photo3"] as? String ?? ""
m.imageUrl4 = doc.data()["photo4"] as? String ?? ""
m.imageUrl5 = doc.data()["photo5"] as? String ?? ""
m.imageUrl6 = doc.data()["photo6"] as? String ?? ""
m.Q1day2live = doc.data()["Q1day2live"] as? String ?? ""
m.QlotteryWin = doc.data()["QlotteryWin"] as? String ?? ""
m.QmoneynotanIssue = doc.data()["QmoneynotanIssue"] as? String ?? ""
m.bucketList = doc.data()["bucketList"] as? String ?? ""
m.jokes = doc.data()["jokes"] as? String ?? ""
// 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)
print("MatchName: \(m.name), distance: \(distance) \tlat: \(m.latitude), \(m.longitude)")
if distance <= radiusInKilometers {
matchingDocs.append(m)
}
} //end for loop
self.matches = matchingDocs
self.usersLoaded = true
}
// 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
.whereField("gender", in: ["Women", "men"])
.whereField("conversations", notIn: [user.name])
//.getDocuments(completion: getDocumentsCompletion)
.addSnapshotListener(getDocumentsCompletion)
}
print("Docs: \(matchingDocs.count)")
}
CodePudding user response:
If you want to add additional conditions to the query you got from GeoFire, you can do so here:
return db.collection("users")
.order(by: "geohash")
.start(at: [bound.startValue])
.end(at: [bound.endValue])
.whereField("gender", isEqualTo: "female")
You may need to add an index for this, so be sure to check the log output for error messages around that (and a link to the Firebase console to quickly create the index).