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.
Related
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.
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.
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.
I have a lot of entry in the same location. I would like only to get the 10 latest added items using Geofire. I know that it can be done easily with firebase using Query.limitToLast() but I don't know how to do it with Geofire.
If it is not possible, do you have any workaround that I can apply ?
There is only one solution for this :
you should begin a query with a small radius,
and each time you reach onGeoQueryReady() ("All data has been loaded"), you increase the radius by a small amount of the geoquery with .setRadius(r) until you reach the limit you want
based on this https://github.com/firebase/geofire-js/issues/59
There is no way to limit the number of keys from Geofire: it will return all keys that fall into the range you query for.
The only thing I can think of is to not insert items if there is already another item in its vicinity. You're essentially clustering items while writing to the database in that case.
I want to get the polygon of a given street using OverPass API. When I use, for instance,
(
way
["name"="Hörnesgasse"];
>;
);node(w);
out body;
Here is a Overpass Turbo link: Overpass Turbo
I get the nodes for a polygon, but they are not in the right order. So I can't save them as a line. Is there any possibility to this better?
Another issue I'm having is that I want to restrict the search for a given city, example "addr:city"="Vienna". Since the nodes don't have a city attribute directly, how could I write a query to get this information?
You will need the way in order to retrieve the order of nodes. This can't work otherwise, imagine a way including one or more nodes twice.
Remove the node(w); part from your query and take a look at the <way> elements. If there are multiple <way> elements then you will have to determine the correct order of them, too. Consecutive ways will share the same node ID at the start or the end.