Querying Nearby Locations with GeoFire
Asked Answered
S

1

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.

Shin answered 4/3, 2017 at 21:25 Comment(8)
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: github.com/firebase/geofire-js/blob/master/docs/…Levey
Thanks @FrankvanPuffelen - it doesn't state in the documentation, but will this return an array of keys depending on the radius?Shin
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? github.com/firebase/geofire-js/tree/master/examplesLevey
Thanks Frank, yes I've checked out the examples many times - I guess I'm still getting used to the fundamentals of Firebase/GeoFire.Shin
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 listenersShin
@KuraiBankusu this post is useful. firebase.googleblog.com/2014/06/geofire-20.htmlChatelain
@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.Chatelain
@Chatelain 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?Shin
T
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) {

            }
        });
Thallus answered 28/5, 2017 at 14:6 Comment(3)
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) ?Lexine
onDataChange(DataSnapshot dataSnapshot) only gets called if all the data has been loaded. Are you loading a list of items?Thallus
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 recyclerviewLexine

© 2022 - 2024 — McMap. All rights reserved.