Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save GeoFire coordinates along with other items in Firebase database?

I'm developing an app and saving some strings like postedAtTime, postedBy, postedOnDate in Firebase database. I want to save the GeoFire coordinates in the same node in which all the above string are saved, so that later I can do query, easily.

Here's the path to which I'm saving all the strings:

databaseReferenceHRequests = firebaseDatabase.getReferenceFromUrl("https://appName-e1a35.firebaseio.com/requests/");

This is how I'm saving it:

// in onButtonClicked method:
postNewRequest(null, imageUID, MainActivity.userName.getText().toString(), time, date, utcFormatDateTime, MainActivity.userEmail.getText().toString(), geoFire);

// the method:
public void postNewRequest(Bitmap bitmap, String imageUIDh, String postedBy, String postedAtTime, String postedOnDate, String utcFormatDateTime, String userEmail, GeoFire geoFire) {
    HRequest hRequest = new HelpRequest(null, imageUIDh, postedBy, postedAtTime, postedOnDate, utcFormatDateTime, userEmail, geoFire);
    databaseReferenceHRequests.push().setValue(hRequest);
}

Here's how it is getting saved in the database:

database structure screenshot

What I want is to save the GeoFire coordinates in the same node, which is -KLIoLUsI0SpQZGpV1h4 here. This is just a push ID and it gets generated randomly.

I tried it by giving this reference:

geoFire = new GeoFire(firebaseDatabase.getReferenceFromUrl("https://appName-e1a35.firebaseio.com/requests/"));

And then pushing it with other items as shown above. But, this saved only GeoFire coordinates and not the other items under the node requests.

So, what should be my GeoFire reference so that it gets saved along with all the data in the same node?

What is going wrong here? Please let me know.

like image 412
Hammad Nasir Avatar asked Jul 13 '16 00:07

Hammad Nasir


2 Answers

Frank's answer is correct, but I want to give an example. Your database structure should be like this.

{
"items" : {
    <itemId> : {
        "someData" : "someData",
        ...
    }
  },
"items_location" : {
    <itemId> : {
        <geofireData> ...
    }
  }
}

To get the data, first you need to do GeoQuery at items_location node and then get the data on the onKeyEntered method. The parameter key is itemId from my example.

geoFire = new GeoFire(FirebaseDatabase.getInstance().getReference().child("items_location");
geoQuery = geoFire.queryAtLocation(geoLocation), radius);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(String key, GeoLocation location) {
         //retrieve data
    }
};    

Hope this helps.

EDIT How to push the item and set the geofire data.

String itemId = ref.child("items").push().getKey();

ref.child("items").child(itemId).setValue(item);

geoFire = new GeoFire(ref.child("items_location"));
geoFire.setLocation(itemId, new GeoLocation(lattitude, longitude));

EDIT Save the item data and geofire data in one API call

GeoHash geoHash = new GeoHash(new GeoLocation(latitude, longitude));
Map<String, Object> updates = new HashMap<>();
updates.put("items/" + itemId, item);
updates.put("items_location/" + itemId + "/g", geoHash.getGeoHashString());
updates.put("items_location/" + itemId + "/l", Arrays.asList(latitude, longitude));
ref.updateChildren(updates);
like image 132
Wilik Avatar answered Oct 04 '22 00:10

Wilik


When you use Geofire, you have two lists of data:

  1. a list of items with their regular properties
  2. a list of geohash indexes and their associated keys, which you query through Geofire

You use the keys to get from the Geoquery results to the regular items. That's why the events for Geofire are called "Key Entered", "Key Exited", etc.

Trying to store them in one node is a bad idea, since you're mixing mostly static data (the properties of your items) with highly volatile data (the geo-location information). Separating the two out leads to better performance, which is why Geofire enforces it.

While there may be use-cases where the properties and geo-data are equally dynamic/static, GeoFire does not support keeping the geo-data and other properties in a single location.

like image 22
Frank van Puffelen Avatar answered Oct 04 '22 00:10

Frank van Puffelen