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).
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.
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.
Basically, my app has posts based on location that can be upvoted/downvoted.
I need to construct a query that returns the top 15 upvoted posts that lie in a specified region, and were made in the last 24 hours. Coming from an sql background, I am finding this unnecessarily difficult to do with the JSON format and firebase's built in query by order and filtering options. I realize i will most likely have to a lot of client side filtering, so I am asking what the JSON structure and query format would be to minimize client side filtering. So far this is what my JSON format looks like:
"posts" : {
"-KPFIsDbf3WUljWvBwi-" : {
"latitude" : 33.64114800203589,
"longitude" : -116.4236003651668,
"time" : 1.47129994542173E12,
"uid" : "wjXpBBJMBVPvRVG48fFkerAw6TD3",
"upvotes" : 0
},
I tried using Geofire, but unfortunately that seems to only have the ability to query by region, and since I want to query by region and time posted (among other things), using Geofire will not scale well.
Here's what I would do in a similar setup, using a combination of GeoFire and Firebase queries:
Step 1 (saving): When saving a post, save it to the database first, using a random ID. Then, grab that ID, create a GeoFire location, and set your post ID as the location key.
Step 2 (querying): This will be a 2 step query
Step 2a: Get all GeoFire locations within specified region. Now, you can grab the keys of all locations from the snapshots and and attach a single data event handler on each.
Step 2b: Maintain a sorted array of post objects by number of upvotes. In the snapshot for single event listener, first check the timestamp to see if it is within the last 24 hours. Next, if the array has a count of less than 15, add your post in sorted position (using an appropriate parsing method). If it already has 15, you'll need to see if the minimum lowest element in the array has more upvotes. If it does not, you'll need to find a place in the array to replace. After you are done parsing through every snapshot from Geofire, you will have your array of posts from the last 24 hours, sorted by upvotes.
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...