Firestore double field query request (and with GeoPoint) - firebase

I have got a collection of documents with two fields: a location (Geopoint) and a distance (Number).
The user input is another location (Geopoint).
I've to return all the documents where the distance between the location of the document and the location of the input is less than the distance of the document.
This tutorial shows how to perform nearby location queries but how can I insert in the equation the distance if it is not given by the user but different for each document?

I came up with a solution.
Instead of saving a geopoint and a radius (representing a circle), I can store the circumscribed square, so I will store two longitudes (geopoint longitude + and - radius) and two latitudes (geopoint latitude + and - radius).
Then I can do a compound query of 4 parts to see if the user geopoint is in the square.
Anyway, this is an imperfect solution because there is a lack of precision in the circle/square approximation, but in my specific case, it doesn't matter. Therefore if in your case precision matters you can save radius (or calculate from square wide), and then make a filter on the objects you queried.
Generalizing, this method can be easily applied to any polygon:
Save in the firestore document the polygon coordinates and the circumscribed rectangle.
Query the documents in Firestore using the four rectangle coordinates
Filter results using the original polygons.

You'll need to calculate the bounding box for your query, based on the position the user entered, and the maximum distance you want to return results for. When using geohashes (as the tutorial does), you'll actually need to calculate four bounding boxes: one in each quadrant from the center of the results that the user entered.
If you've never done this, it can be a bit hard to do it yourself, which is probably why the tutorial author doesn't cover it. But there are multiple Geo-libraries for Firestore which do this for you, and I'd highly recommend checking them out.
If you'd like to learn more about how the whole searching process works, I recommend checking out the video of my talk a while ago: Querying Firebase and Firestore based on geographic location or distance.

Related

How to return x nearest people in flutter with Firebase?

Is it possible to query a certain number of nearest locations from a cloud firestore database in Flutter? The geoflutterfire package only appears to allow you to query locations within a radius. Is the only solution to slowly increase the radius until an acceptable number of users is found? This sounds like a very unclean solution. Are there other packages or methods that will give you this functionality?
Due to the nature of how the Geo*Fire packages work, they cannot return the X nearest results.
The common pattern:
Start with a reasonable range, client-side order the results on distance, and then return the top X.
If you got too few results, try again with a larger range.
Increasing the range is not as expensive in Firestore as you may think, as the documents for the smaller range will already be in the client-side cache after the first geoquery.

Is there an easy and efficient way to query geopoints on Firebase?

I'm currently developing a Flutter app based on geolocation, I need to query based on a variable radius.
Every document in my database has a field named "position" with a geohas and a geopoint, the problem is that the only library I know is geofire, but this is not really efficient, because If I query on a certain radius (10 km) and than I need to query from 10km to 20km I can't: I can just query again with a fixed 20km radius, which means I query (and pay) first 10km for nothing because I already had them.
the problem is that the only library I know is geofire,
As far as I know is the only one for the moment.
If I query on a certain radius (10 km)
This is possible for sure.
than I need to query from 10km to 20km I can't
You cannot query but you can get the locations from 10km to 20km, which I think is what you want. Since you already have the locations within 10km, when you query the locations from 0km to 20km, every location that you get is new, which means that is located from 10km to 20km.
which means I query (and pay) first 10km for nothing because I already had them.
No, you don't pay for those location that are within 10 km since those locations are coming from cache. So when you perform the second query (from 10km to 20km) you'll be charged only for the locations within that range.
The problem comes if you want to get the locations from 10km to 20km directly without having the locations from 0km to 10km. In that case, you get all locations from 0km to 20km, and then perform another query to get all locations from 0km to 10km. Now, to have all location from 10km to 20km, simply remove all locations that you get from the second query. So in both cases, you need to perform two queries.

Query for nearby locations

I am using Firebase to store users with their last scanned latitude and longitude.
An entry looks like this:
"Bdhwu37Jdmd28DmenHahd221" : {
"country_code" : "at",
"firstname" : "John",
"gender" : "m",
"lat" : 11.2549387,
"lon" : 17.3419559
}
Whenever a user presses a specific "search" button, I want my Firebase function to fetch the people nearest to the person who sent the request.
Since Firebase only allows for querying after one field, I decided to add the country_code, to kind of have some range-restrictions and query for that field. But it is still super slow when I load every user of a specific country and then check for the smallest distance between a given user and all the other users in the same country.
Already with 5 users, the function takes like 40 seconds to achieve the results.
I have also read about compound Indexes, but I would need to somehow combine the latitude and the longitude and query for both fields.
Is there any way to either get a second and third query involved here (e.g. search for the same country_code, and then for a similar longitude and latitude) or do I have to solve this inside my server code ?
The Firebase Database can only query by a single property. So the way to filter on latitude and longitude values is to combine them into a single property. That combined property must retain the filtering traits you want for numeric values, such as the ability to filter for a range.
While this at first may seem impossible, it actually has been done in the form of Geohashes. A few of its traits:
It is a hierarchical spatial data structure which subdivides space into buckets of grid shape
So: Geohashes divide space into a grid of buckets, each bucket identified by a string.
Geohashes offer properties like arbitrary precision and the possibility of gradually removing characters from the end of the code to reduce its size (and gradually lose precision).
The longer the string, the larger the area that the bucket covers
As a consequence of the gradual precision degradation, nearby places will often (but not always) present similar prefixes. The longer a shared prefix is, the closer the two places are.
Strings starting with the same characters are close to each other.
Combining these traits and you can see why these Geohashes are so appealing for use with the Firebase Database: they combine the latitude and longitude of a location into a single string, where strings that are lexicographically close to each other point to locations that are physically close to each other. Magic!
Firebase provides a library called Geofire, which uses Geohashes to implement a Geolocation system on top of its Realtime Database. The library is available for JavaScript, Java and Objective-C/Swift.
To learn more about Geofire, check out:
this blog post introducing Geofire 2
the demo app that used to show local busses moving on a map . The app doesn't work anymore (the data isn't being updated), but the code is still available.
this video and documentation on how to implement geoqueries on Cloud Firestore.

Mapping GPS coordinates to an area

I have devices moving across the entire country that report their GPS positions back to me. What i would like to do is to have a system that maps these coordinates to a named area.
I see two approaches to this:
Have a database that defines areas as polygons stretching between various GPS coords.
Use some form of webservice that can provide the info for me.
Either will be fine. It doesn't have to be very accurate at all, as i only need to know the region involved so that i know which regional office to call if something wrong happens with the device.
In the first approach, how would you build an SQL table that contained the data? And what would be your approach for matching a GPS coordinate to one of the defined areas? There wouldn't be many areas to define, and they'd be quite large, so manually inputting the values defining the areas wouldn't be a problem.
In the case of the second approach, does anyone know a way of programatically pulling this info off the web on demand? (I'd probably go for Perl WWW::Mechanize in this case). "close to Somecity" would be enough.
-
PS: This is not a "do the work for me" kind of question, but more of a brainstorming request. pseudo-code is fine. General theorizing on the subject is also fine.
In the first approach, how would you build an SQL table that contained
the data? And what would be your approach for matching a GPS
coordinate to one of the defined areas?
Asume: An area is defined as an closed polygon.
You match the GPS coordinate by simply calling a point inside polygon method, like
boolean isInside = polygon.contains(latitude, longitude);
If you have few polygons you can do a brute force search through all existing polygons.
If you have many of them and each (ten-) thousands of points, the you want to use a spatial grid, like a quadtree or k-d tree, to reduce the search to the relevant polygons.
method.
this process is called reverse geocoding, many services providers such as google, yahoo, and esri provide services that will allow to do this thing
they will return the closest point of interest or address, but you can keep the administrative level you are interested in
check terms of use to see which service is compatible with your intended usage

Find objects by pointing in a direction

I have a specific problem, and I find it hard to find a solution!
Using a GPS Device I can find my current position on earth. I need to be able to point to a direction (a compass on iPhone or similar device) and find what important objects (locations) are in that direction! Assume that I do have all those locations stored in a database.
Assuming you have a location and a direction, your goal is to find what items in your database are adjacent to the location, in the appropriate direction.
Obviously, you could scan through every element in your database, and answer for each one, "Is this in the region?". The real magic is efficiency; how you index the data in the database such that you can answer that question without having to examine every record.
A great example of this is in MongoDB. However it's implementation does not handle direction, so you will need to filter the results. You will use the database to get all objects within x distance of you, and will filter out those elements which are not in the appropriate direction.
If you cannot use a database engine with native geospatial indexing, you'll have to implement it yourself. As mentioned in the comments, the Haversine function is used to compute distance on a sphere (in this case, the earth). Rather than computing the distance between every point and yourself, you could begin by eliminating any elements which are grossly out of range, e.g. (your latitude + your search distance) < (the objects latitude). Then use the Haversine to filter further. You could also use a geospatial hashing function to do most of the work beforehand.
Once you have all of the elements within range, you can convert the x-y coordinates in your database into the polar coordinates. In short:
arctan((item_y - users_y) / (item_x - users_x)) = the angle between the item and the user
If you compute this for every item within 'range' of the user, and filter out any elements which are not within some bounds of the compass angle (+/- 20 degrees, for example), you will get the elements you need.
If efficiency is still an issue, you can get more clever by immediately invalidating any elements which, for example are on the wrong side of the user (if the user is facing west, than any elements which have an x coordinate higher than the user cannot possibly be in his view). Depending on your programming language, it may also be more efficient to use a static table of arctans with a lower degree of accuracy than is commonly provided.
If you are particularly clever, you may also find ways of indexing the data by angle, which will further lower the computation required.

Resources