I have a ios location based app. A user needs to be able to see nearby users within a certain radius. is there a way to read the nearby user documents in batches so that i don’t unnecessarily load too many documents that the user won’t scroll through. So first show 20 nearby users. then when the user scrolls down and reaches the last (20th) item in the collection, load 20 more nearby users who have not already been loaded (still within the desired radius).
Something like this is easy to do if i’m just reading users in by their join/sign up date. but i’m not sure how to do this for a location based query.
Is my only option to query on a small radius and then increase the radius (which will load some of the documents that have already been loaded from the database in previous query) and then deal with duplicate documents on the client side?
2
Answers
If you look at the documented solution for implementing geoqueries on Firestore, you’ll see that it doesn’t load the documents in order of proximity but in geohash blocks that looks like this:
The only workaround is indeed to start with a smaller radius to load the documents who are nearer, and expand the radius until you have loaded the required number of documents.
Also see:
Geohashes are sort of an ancient technology. There are much more efficient ways to geoquery and one such way that pairs very nicely with Firestore is Uber’s H3, Uber’s open-source geospatial library that the Uber app itself uses. The library is written in C but C plays very nicely with Swift. I use it in an iOS app of my own and it does exactly what you’re looking for.
The concept is simple. H3 tiles the globe in hexagons (of varying sizes from very small to very large depending on how granular you want the geoquery to be). The brilliance of this is that you can cluster these tiles together (around a central tile) to form a larger hexagon. And if the individual tiles are small enough and the cluster they form is big enough, the coverage of this shape will very closely resemble a circle. And this is why H3 is incredibly efficient because there is exceedingly little over-query when properly tuned.
And so to make this play nicely with Firestore, simply give each user’s document a property that represents their proximity, which is a cluster of tiles around the tile that represents their current location (this property would be an array of 64-bit integers). And so to make a geoquery, you ask H3 for the device’s current tile by giving it lat-lng coordinates (which will return a 64-bit integer) and then ask Firestore to find all documents where this 64-bit integer is contained in any other user’s proximity array. And you can, of course, paginate these results which is what you’re ultimately looking for.