I'm producing a project with Firebase Realtime Database.
I have to post pictures with timestamp, latitude and longitude, and search for pictures in a radios from my position, ordered by timestamp and with the value of the timestamp 1 days from now.
Is Firebase Realtime Database + Geofire right for me?
I cannot figure out how to make queries.
Thank you!
The Realtime Database only supports one dimensional queries. So, if you did want to use
the RTDB, you'd need a two-stage query.
geoquery all the pictures in your given center/radius.
for each of these pictures, query all the data for that picture.
Once the data arrives for all the pictures, filter/sort client side.
RTDB structure would be something like:
pictures/{pic_id}: {
timestamp:,
name:
[,...]
},
geofire_pictures/{pic_id}: <geofire data>
With that said, I think RTDB would be a fine choice if you expect your
result set sizes to be managable. If you need to scale, I would suggest waiting for Firestore's geoquery functionality.
Related
I am currently using Firestore for my iOS app and I need to implement a scalable solution for my posts feed. I need to get posts within say 20 miles, order them by date, and limit the amount of posts fetched for pagination. Any and all database solutions would very much appreciated! Thank you!
As a low budget/time alternative to libraries, we have implemented storing the first few digits of lat/long coordinates as a document or collection name and then accessed data that way. The first decimal place gives resolution to around 10 miles or so (exact values for longitude change depending on what latitude you are at). So in your database you could have a collection or document named something like +33.6-112.0. This would mark a reference in Firestore to put all data within (33.8 N, 112.0 W). Be careful with how you round the exact location data before placing it in the respective document or collection.
Then you can retrieve all data at any location you want. This may not give you exactly 20 miles, but some client side sorting can handle that. Note you could make the reference go to any decimal place necessary to achieve the level of precision you are looking for to minimize data base calls (to save you money) and minimize impact on the user's cell data plan.
This is a rather simple solution with limitations, maybe for an MVP, and if not careful could pull way more data than anticipated.
Below is a chart showing the approximate physical distance between each decimal place at the equator. So for example, the distance between (33.3 N, 0 W) and (33.5 N, 0 W) would be about 14 miles.
Neither of those databases have native geospatial querying capabilities. You would have to use some sort of add-on library to help with that. Geofire and Geofirestore are popular for this.
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.
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).
Firebase just updated their sdk to 3.x and the current version of GeoFire 2.x doesn't work.
What I would like to know is the best way to store geo location values so that I can query firebase so that we only return location with in a defined radius around the user.
Example: user defines that they would like all items that are within 20 miles or less from them.
I wonder if I could store a single value from the latitude and longitude that would allow me to quickly query for this data? Or maybe that isn't the right approach ?
It is not possible using pure firebase without implementing some sort of geohash (it is what geofire does). You could use an externa index stored in elastic search or in redis for example
I have a database of posts in firebase, and each has a timestamp and a rating.
i know how to order by time OR by rating, but would it be possible to order by rating, then limit by time. ie. show highest rated posts over the last week?
ie.
Ref.queryOrderedByChild("rating").observeSingleEventOfType(.Value, withBlock: {...}
would order by rating, but how would i then limit the query by time, and not rating?
Unfortunately, Firebase does not support cross referencing nor server-side logic, so you'll probably have to query by the more specific value, pull the data down, then sort the rest client side.
Alternatively, you could also try to get creative with GeoFire (firebase's cross referencing solution for latitude/longitude location querying), though that'll the hackiest solution ever...
At the moment I have a Fusion Table with 3 columns:
Column A (text): name of a store
Column B (location): city of that store
Column C (number): radius in which the store advertises (so for instance 5km around store location).
Here is a link to the table:
https://www.google.com/fusiontables/DataSource?docid=15YqM0NN0hCc9IfSUfdOiVqS1sFIKehtaYAjg8nU
Now what I would like to do is visualize these advertising radius-es of all these stores on a map. As the radius-es vary for each store (5km for store 1, 10km for store 2, etc.), I have no idea how to start working on this with the API.
I would really appreciate any help here.
With your current setup this is not possible at all, because your Location-colum is geocoded, it's not possible to access the geocoded LatLng in any manner.
Even when you had the LatLng's it wouldn't be possible to visualize a circle via a FusionTablesLayer, because circles are not supported by KML.
So the only thing you can do is:
Request the complete data(may be done via AJAX, JSONP is supported), geocode the City-column an draw a google.maps.Circle based on the returned LatLng and the radius stored in the Number-column(of course it would be better when you had stored LatLng's instead of city-names, because you wouldn't have to geocode the cities each time).