1

Since native GeoQueries are not yet supported, I've thought of a possible solution but would like to know of its validity and effectiveness.

What I want: I have a collection of about 2000 documents, each containing a Geopoint. I would like to query for example, the closest 20 documents to the users current location.

Possible Solution: Can I create another document in the collection and have that as my 'index'. Each field name would be the String of each documents ID. The value of each field would be the corresponding Geopoint. I would then only need 1 read operation when the app is opened... Can I then use a function to work through the 2000 document fields to calculate and order the distance of each location from the user? Finally, could I then take the closest 20 results and then just create a listener and pull only those results?

Edit: Have attempted my suggestion. Gave up after running into constant issues. I got the whole index document working, and was able to download it, arrange it to find the closest locations and the relevant doc id. However I had a lot of issues with using the array of doc IDs to set listeners to. I used a for loop to loop through each ID in the array and set a listener for each, but it only ever did the first one and random crashes kept happening. Also I noticed it took a fair bit longer to get the doc.... So, I decided to ditch the high accuracy solution and just query the geopoints to find locations within a square around the user.

NicCoe
  • 409
  • 4
  • 17

1 Answers1

3

I think that the easiest way will be query using the Firestore Geopoints, you can achieve it doing this:

fun Query.getNearestLocation(latitude: Double, longitude: Double, distance: Double): Query {
    // ~1 mile of lat and lon in degrees
    val lat = 0.0144927536231884
    val lon = 0.0181818181818182

    val lowerLat = latitude - (lat * distance)
    val lowerLon = longitude - (lon * distance)

    val greaterLat = latitude + (lat * distance)
    val greaterLon = longitude + (lon * distance)

    val lesserGeopoint = GeoPoint(lowerLat, lowerLon)
    val greaterGeopoint = GeoPoint(greaterLat, greaterLon)

    val docRef = FirebaseFirestore.getInstance().collection("locations")
    return docRef
            .whereGreaterThan("location", lesserGeopoint)
            .whereLessThan("location", greaterGeopoint)
}

It's also wrote on Kotlin. This code is a Kotlin translation from the code made by Ryan Lee on this post.

halfer
  • 19,824
  • 17
  • 99
  • 186
Francisco Durdin Garcia
  • 12,540
  • 9
  • 53
  • 95
  • Thanks, I have seen a couple examples of that answer (not sure why a mile has to be used though). Appreciate the Kotlin translation, saves me having to do it. The only thing is that I believe this provides locations within a 'square' around the users location. I'm currently trying to implement a solution inline with my question/suggestion, but I will be sure to compare it to your solution and test the differences in completion time and accuracy. – NicCoe Jun 04 '18 at 10:33
  • Thank you to accept my answer as correct. Did you found the way to measure your locations in the way that you wanted? – Francisco Durdin Garcia Jun 08 '18 at 08:24
  • That's alright, your solution was much easier and faster to implement, and the accuracy difference won't matter for now. I used almost your code exactly, but changed to support km instead of miles. The query works great now. Thanks. – NicCoe Jun 08 '18 at 22:39