1

Currently, I'm using parts of the GeoFirebase library along with Firestore to allow for geoquerying. When I set the geohash of a post, I do it as such if let geoHash = GFGeoHash(location: location.coordinate).geoHashValue {

However, to make the geohash querying less specific, I'm planning on truncating part of the geohash when I query; currently, the query looks similar to this

 var geoQuerySpecific = GFGeoHashQuery()
        let geoQueryHash =  GFGeoHashQuery.queries(forLocation: (lastLocation?.coordinate)!, radius: (30)) as! Set<GFGeoHashQuery>

        for query in geoQueryHash {
            geoQuerySpecific = query
            print("the key is this um \(geoQuerySpecific)")
        }
        print("the starting value is \(geoQuerySpecific.startValue)  and the end value is \(geoQuerySpecific.endValue)")
        let nearQuery = Firestore.firestore().collection("stuff").order(by: "g").whereField("g", isGreaterThanOrEqualTo: geoQuerySpecific.startValue).whereField("g", isLessThanOrEqualTo: geoQuerySpecific.endValue)

As you can see, this won't work correctly as there are multiple items in the geoQueryHash. I've thought about truncating the last four digits/letters from the geohash when I am setting it in firebase, however, that won't be specific enough. To get the closest posts, would it be best to set the geoHashes in the database as I currently am, then, when retrieving the stuff, make the start value the most specific geohash for the query and then make the end value the truncated version of the geohash, as to start by getting the closest posts and end with the broadest?

I can limit the Firestore query to 50, so then I can retrieve the 50 posts from closest to furthest... is my understand of geo hashing correct? Would this be feasible?

Conceputally, if there were a way to store geohashes as integers than I could make the firestore query start at the largest integer (i.e. most precise Geohash) and then work order the query by descending until it gets to the least precise intenser (broadest geoHash) and then limit it to 50.

Raim Khalil
  • 387
  • 3
  • 19

1 Answers1

4

GeoFirestore uses geohashes to be able to select documents that are within a range of geohashes, which is roughly the same as an area on the map. There is no way to retrieve those documents within a specified order from within that area with just a geoquery. If you want to have the documents sorted by distance, you will have to do that after the geoquery, in your application code.

If you want to learn more on why that is, have a look at a talk I gave a while ago: Querying Firebase and Firestore based on geographic location or distance. In it I explain how geohashes work, how they allow you to select documents in a certain geographic range, and why you can't do the more complex query on Firestore (or Firebase's original realtime database).

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I understand that aspect of it, however I’m considering them from the perspective of alphanumeric strings that could be sorted. For instance, if I started at gh67 that would be the most general area, but if I went to gh674df5 that would be more specific. From that perspective, is it not possible to do a query starting at gh674df5 and ending at gh67? Is it possible for alphanumeric strings to be sorted that way? – Raim Khalil May 20 '19 at 03:43
  • 1
    In some edge cases you may be able to select a subrange like that, but not in general. But it also wouldn't necessarily return the items from nearest to furthest. – Frank van Puffelen May 20 '19 at 03:47
  • So basically there is no way to query from closest to furthest, even if I sort by different length Geohashes ? – Raim Khalil May 20 '19 at 03:49
  • 1
    The geohashes in the document are all of the same length. You could add multiple geohashes to each document, each for a specific resolution. But it still wouldn't help for this use-case. – Frank van Puffelen May 20 '19 at 03:58
  • What if, for instance, every time a user posts I get his geoHash, lets say it has 9 digits. I can store the 9 digit version of the geohash, the 8 digit prefix, the 7 digit prefix, 6, 5, and so on. Then, when I query for posts, I can get the users current geohash and query for that. If there are not enough documents as I want to fill the feed, I knock off one digit and query the 8 digit prefix of the geohash, something like `postsReference.whereField("(geoHash), isGreaterThan:"").limitTo(50)`, and then if that query doesn't return 50 documents go to a broader geoHash. – Raim Khalil May 20 '19 at 04:02
  • For further elaboration, as such `postsReference.whereField("(geoHash9digit), isGreaterThan:"").limitTo(50)` then `postsReference.whereField("(geoHash8digit), isGreaterThan:"").limitTo(50)`, then `postsReference.whereField("(geoHash7digit), isGreaterThan:"").limitTo(50)` – Raim Khalil May 20 '19 at 04:07
  • alternatively , as that may lead to repeated observers (first a post is getting observed at the specific geohash, and it’s still there when you zoom out) what if I instead did a search type of thing. I query first for the square the user is in, it that doesn’t work then query the geohash above it below it to the right and to the left and if that still doesn’t work add more observers for the Geohashes around those? – Raim Khalil May 20 '19 at 04:22
  • 1
    Storing resolution at multiple resolutions isn't enough, since the center of your query will seldom coincide with the center of the geohash. But storing multiple resolutions is essentially what a solution like S2 does. – Frank van Puffelen May 20 '19 at 14:13
  • Thanks for your help. Does this structure make sense? When a user posts, get his geohash and the surrounding 8 geohashes. Add the first geohash as a field as geohash1: primary. Then I can add the other 8 geohashes as geohash2:secondary, geohash 3:secondary. When the user queries, I can first query for locations with primary, meaning it was posted in the same geohash. If nothing returns, I can geohash for any posts that have the users geohash as a secondary? – Raim Khalil May 20 '19 at 14:16
  • 1
    I find it very hard to reason about geohashes in the abstract, so definitely recommend giving things a try. If you're heading down this path, check out S2, which solves the edge cases of geohashes around the poles, is more focused on multi-resolutions, and reduces the amount of over-reading that all solutions have. – Frank van Puffelen May 20 '19 at 14:51
  • sorry, one last thing. With S2, would it be possible to perform queries similar to the query in my question (starting at a specific point and then working your way out)? Does S2 work that way where I can order itnegers such as from 109876 to 10987637 ? – Raim Khalil May 20 '19 at 15:01