6

I'm having a difficult time understanding how GeoFire queries nearby locations;

I'm building a geo-based app that will fetch nearby locations based on the users location. My data is structured as follows

locations
    -Ke1uhoT3gpHR_VsehIv
    -Kdrel2Z_xWI280XNfGg
        -name: "place 1"
        -description: "desc 1"
geofire
    -Ke1uhoT3gpHR_VsehIv
    -Kdrel2Z_xWI280XNfGg
        -g: "dr5regw90s"
        -l
            -0: 40.7127837
            -1: -74.00594130000002

I can't seem to comprehend the whole idea of "tracking keys" and locations leaving & entering GeoQueries. (Perhaps this concept is more related to Uber-like functionality)

Assuming the locations above are nearby, how exactly would I use my own lat and long coordinates to fetch them? I'm sure I'm misinterpreting GeoFires documentation but I'm just not seeing it.

Clay Banks
  • 4,483
  • 15
  • 71
  • 143
  • After you insert the data under the `geofire` key with Geofire, you can get the keys in a specific area with a geo-query. For example `var geoQuery = geoFire.query({ center: [10.38, 2.41], radius: 10.5 });` For this example and much more, see the Geofire documentation: https://github.com/firebase/geofire-js/blob/master/docs/reference.md#geofirequeryquerycriteria – Frank van Puffelen Mar 04 '17 at 23:48
  • Thanks @FrankvanPuffelen - it doesn't state in the documentation, but will this return an array of keys depending on the radius? – Clay Banks Mar 05 '17 at 01:50
  • No, it will not return an array. Firebase is a *realtime* database, so that array would constantly be updated (which isn't possible). Instead it fires events. Did you check out the examples? https://github.com/firebase/geofire-js/tree/master/examples – Frank van Puffelen Mar 05 '17 at 15:41
  • Thanks Frank, yes I've checked out the examples many times - I guess I'm still getting used to the fundamentals of Firebase/GeoFire. – Clay Banks Mar 05 '17 at 15:44
  • Just to clarify, events like the 'key_entered' event are necessary to the geoQuery to get nearby locations correct? If so, than the line you provided: `var geoQuery = geoFire.query({ center: [10.38, 2.41], radius: 10.5 });` won't actually contain data about nearby locations on its own, but in combination with event listeners – Clay Banks Mar 05 '17 at 16:50
  • @KuraiBankusu this post is useful. https://firebase.googleblog.com/2014/06/geofire-20.html – vzhen Mar 17 '17 at 10:18
  • @KuraiBankusu you don't have to track each key yourself. A quote from post above. `GeoFire is smart about how it looks for keys within the query. It does not need to load all of the GeoFire data into memory.` – vzhen Mar 17 '17 at 10:41
  • @vzhen I get that, but then how would you go about appending the distance of many locations in a radius to their respective fire base objects? Do you not need two separate arrays for this? – Clay Banks Mar 17 '17 at 11:41

1 Answers1

9

To get all the locations which are nearby, first we get a Database reference to where we save our GeoFire locations. From your question, it should be

DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("geofire");

Next we create a GeoFire instance with our GeoFire location reference as the argument

GeoFire geoFire = new GeoFire(ref);

Now we query the GeoFire reference,geoFire using it's queryAtLocation method The queryAtLoction method takes 2 arguments:a GeoLocation object and the distance range. So if we use 3 as the distance range, any location which is 3kilometers away from the user will show up in the onKeyEntered(...) method.

NB: The GeoLocation object takes 2 arguments: latitude and longitude. So we can use the user's latitude and longitude as the arguments.

        GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(userLatitde, userLongitude), 3);
        geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
            @Override
            public void onKeyEntered(String key, GeoLocation location) {
                //Any location key which is within 3km from the user's location will show up here as the key parameter in this method 
                //You can fetch the actual data for this location by creating another firebase query here
    Query locationDataQuery = new FirebaseDatabase.getInstance().child("locations").child(key);
    locationDataQuery..addValueEventListener(new ValueEventListener() {
                        @Override
                        public void onDataChange(DataSnapshot dataSnapshot) {
                            //The dataSnapshot should hold the actual data about the location
    dataSnapshot.getChild("name").getValue(String.class); //should return the name of the location and dataSnapshot.getChild("description").getValue(String.class); //should return the description of the locations
                        }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {

                    }
                });
            }

            @Override
            public void onKeyExited(String key) {}

            @Override
            public void onKeyMoved(String key, GeoLocation location) {}

            @Override
            public void onGeoQueryReady() {
                //This method will be called when all the locations which are within 3km from the user's location has been loaded Now you can do what you wish with this data
            }

            @Override
            public void onGeoQueryError(DatabaseError error) {

            }
        });
José Morano
  • 150
  • 1
  • 5
  • Can you please tell how can we be notified when all our actual data(not geo data) is retrieved and we can notify recycler,or it is ok to do it in `public void onDataChange(DataSnapshot dataSnapshot)` ? – Levon Petrosyan Apr 06 '18 at 07:17
  • `onDataChange(DataSnapshot dataSnapshot)` only gets called if all the data has been loaded. Are you loading a list of items? – Aryeetey Solomon Aryeetey Apr 06 '18 at 09:57
  • But we are calling `onDataChange(DataSnapshot dataSnapshot)` in `onKeyEntered(String key, GeoLocation location)` callback which may triggered several times,so for each `key` `onDataChange(DataSnapshot dataSnapshot)` will be called and I would like to add each `data` object to my recyclerview – Levon Petrosyan Apr 06 '18 at 10:21