I would like to query my data set for results that occur within a date range and location range (geohash range). I am struggling to find a good solution.
I am using GeoFire and have tried various methods of segrigating my data either by date or location. It's easy enough to build a node for each day and plop geohashes inside but how can i then page through that data without downloading all 5000 results in the city of NYC for example?
If i could sort first on the geohash and then on the date this would be easily achieved but i can not do that in firebase or any NoSQL database.
Someone must have encountered this multirange query problem and i hope you can share what you learned.
Thanks
It's easy enough to build a node for each day and plop geohashes inside but how can i then page through that data without downloading all 5000 results in the city of NYC for example?
Please let me know if I'm misinterpreting your question. Would you be able construct a DatabaseReference to the node representing a specific day, creating a GeoFire object and a GeoQuery, repeating for each day?
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("path/to/dayNode");
GeoFire geoFire = new GeoFire(ref);
GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(37.7832, -122.4056), 0.6); // Use this for addGeoQueryEventListener() or something else
// See https://github.com/firebase/geofire-java
This would allow you to only download the locations in the 0.6 km surrounding 37.7832, -122.4056. To prevent downloading too many results at once, start with a small radius and increase from there?
As a side note, I believe Firebase Firestore allows for multiple cursor conditions such as:
db.collection("locations")
.orderBy("locationhash")
.orderBy("date")
.startAt(locationHash, startDate)
.limit(25);
Unfortunately, I don't think you would be able to specify a radius while sorting by date and paginating unless you extended the work done in GeoFire or GeoFirestore. Hopefully someone else has a better idea.
Related
I am using CBL for Android. I have the latitude and longitude values that the user saved earlier. And there are also values for the location the user has marked on the map.
I need to make a query on the database using the location information the user has selected on the map. So if the records in the database are located near the location the user chose, I want to show this.
How can I do that. I have no idea how to query this in CBL. I would be very glad if you could help. Thanks in advance.
There is no out-of-box query support. From discussion thread posted here,
It’s possible to do bounding-box queries without specialized indexes;
for example (pseudocode) loc.x BETWEEN $x0 AND $X1 AND loc.y BETWEEN
$y0 AND $y1. With regular indexes on loc.x and loc.y (as opposed to
R-trees) this isn’t very efficient, but it’s workable as long as your
data set isn’t too large.
I'm making an android app where user can find a book in his/her vicinity and buy it if interested. I am using firebase and geoqueries/geofire.
I want to make a SearchActivity where user can search a book by it's title in his/her vicinity.
my Firebase Database Structure looks like :
books
PushKey
g:
l:
0:
1:
name:"some book name"
If i try to query this with some book name, it works fine using :
myRef.orderByChild("name").equalTo("some book name").addChildEventListener()....//The rest of the code here...
If i try to query nearby books,then also it works fine using :
geoQuery = geoFire.queryAtLocation(myLocation, 10);
I'm stuck at combining these two.
How can i search for a specific book name only in the vicinity?
For example : I want to search a book whose name is "ABCD" and is in a radius of 10km.
OR
Search a book by name and tell which one is nearest(In case several books are uploaded with same name at different locations).
Is it possible to do so? If not, what workaround(maybe other than firebase, but has to cheap and affordable) can i opt for where i can achieve this desired result?
The Firebase Database can only query by a single property. The fact that GeoFire does something that is seemingly at odds with that (querying by longitude and latitude) is because it combines these values into a single property in a magical format called a geohash (the g property in your JSON).
Combining values into a single property is the only way to get Firebase to filter on multiple values. For example, you could prefix the g property with your book title to get some book name_geohashvalue and could then filter on that.
The two main problems with that:
This only works if you know the entire book title, you can do a prefix match on the title, as you'll already need to use the prefix match for the geohash.
This is not built in to GeoFire, so you will have to fork that library and build it yourself.
If you do try to do this yourself, and get stuck, we can try to help. But fair warning: this won't be trivial, and you'll need to understand how geohashes, geofire, and Firebase's query model work quite well. For an intro, I recommend watching the video of my talk on performing geoqueries on Firebase and Firestore.
If you want something a bit less involved, you have two main options:
Retrieve all nodes within range, and then filter for the book title client-side.
Store a separate GeoFire tree for each book title, so that you can initialize your GeoFire object based on the book title, and only get keys within range for that specific book title.
Between these two, I'd recommend starting with #1.
I am currently working on a program which requires containing location of users with Android Studio. In my users collection, I have location informations as geopoints for each user documents. I need to get all users which are in radius range of a circle. I found GeoFireStore of imperiumlabs -https://github.com/imperiumlabs/GeoFirestore-Android- for this geographic location processes. I can set and get location of a document(single user). But I want to define a center and check if there is/are anyone within the range.
As I understand I need to use geo query event listener as follows;
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {...}
It has Key Entered, Key Moved, Query Ready, Query Error methods, but I couldn't manage what and how to use. I need returned informations of documents(users) which(who) are in my defined range. This way, I can show them main user.
For short words; can someone help me about understanding event listeners of geofirestore?
Thanks for your precious time.
After spending more and more hours I finally solved my issue with
public void onDocumentEntered(DocumentSnapshot documentSnapshot, GeoPoint location) {}
in the GeoQueryDataEventListener Interface. This method works recursively until meeting the requirements of query and I put it in onCreate. I just listed document_id's with documentSnapshot.getId() and tranferred them to an arraylist with mList.add(documentSnapshot.getId()) . Hope this can help someone take care.
I am using firebase database and collecting users with their GPS coordinates and last timestamp from server side. Such as
+users
userId
userLocation
lastTimestamp
Well I want add a firebase Rules which is a user can read only who close to him (for example around the 1 km) and in time (such as people who has been there in for 30 min ). Is that possible to solve in firebase rules segment with newData and validate comments?
Store and retrieve the locations using geofire.
https://github.com/firebase/geofire-java
Setting location data
geoFire.setLocation("userId", new GeoLocation(37.7853889, -122.4056973));
Geo Queries
// creates a new query around [37.7832, -122.4056] with a radius of 0.6 kilometers
GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(37.7832, -122.4056), 0.6);
And to add a time limit change the read rule for your specific data.
// only messages from the last 30 minutes can be read
".read": "data.child('timestamp').val() > (now - 18000000)",
I think its in geofire where you set the radius.
I'm also new to firebase so I'm not really familiar with it.
well check this one.
https://github.com/firebase/geofire
I'm migrating an application that was using Mysql to firebase, and I managed to migrate it almost all, just missing the part of search, I did not quite understand how it works. I'm trying to do this query below in firebase.
SELECT *, (6371 * acos( cos(radians(?)) * cos(radians(latitude)) * cos(radians(?) - radians(longitude)) + sin(radians(?)) * sin(radians(latitude)) )) AS distance FROM usuario ORDER BY distance
What I'm trying to do is pass the latitude and longitude of my User to firebase and he returns me all users ordering the nearest to the farthest.
Note: This is not the same query that I use in my application, that I just find on google and do not know if this work, but you can get an idea of what I'm trying to do.
Note ²: English is not my native language :P
The example SQL query you provided uses a capability of SQL that does not exist in Firebase: the ability to calculate an expression using the column values for each row in the table and then use the value of that expression to filter and sort the query result.
I don't see a way to use Firebase to perform the type of query you want.
You might want to take look at the Geofire library. I have not used it and its capabilities seem to be related to proximity filtering, not the sort-by-distance feature you need, but maybe you can adjust your requirements to make use of its features.
I concur with Qbix and would normally post this as a comment, but I want to make sure the Geohash comment doesn't get lost in the small-text shuffle.
GeoFire uses Geohash codes to create its keys and allow range-matching. For basic apps this may be fine, but the second you go beyond the US this creates a lot of trouble because it doesn't work well around the equator and Prime Meridian (UK). See the Wikipedia Page on Geohash for details, specifically: Edge case locations close to each other but on opposite sides of the 180 degree meridian will result in Geohash codes with no common prefix (different longitudes for near physical locations)..
Firebase is an amazing product, but not a one-size-fits-all tool. If you need good Geo-based search/matching, use a tool like ElasticSearch, MySQL, Algolia, etc. that support it directly. Reducing the number of components in cases like this doesn't decrease complexity, it increases it.
You can use Geofirestore library
https://github.com/geofirestore/geofirestore-js
here is the example used:
import * as firebase from 'firebase/app';
import 'firebase/firestore';
import { GeoCollectionReference, GeoFirestore, GeoQuery, GeoQuerySnapshot } from 'geofirestore';
// Initialize the Firebase SDK
firebase.initializeApp({
// ...
});
// Create a Firestore reference
const firestore = firebase.firestore();
// Create a GeoFirestore reference
const geofirestore: GeoFirestore = new GeoFirestore(firestore);
// Create a GeoCollection reference
const geocollection: GeoCollectionReference = geofirestore.collection('restaurants');
// Create a GeoQuery based on a location
const query: GeoQuery = geocollection.near({ center: new firebase.firestore.GeoPoint(40.7589, -73.9851), radius: 1000 });
// Get query (as Promise)
query.get().then((value: GeoQuerySnapshot) => {
console.log(value.docs); // All docs returned by GeoQuery
});
where {1000} in the query is the radius of location search