Geo-Firestore Query with Native Query

Chintan Patel
Kotlindroid
Published in
4 min readAug 30, 2019

--

Optimizing query reads, faster the response and feel the code in native

Geo-Firestore

After the lot of research and working on Geo-Firestore query to get all the nearest list from the give location within a given distance, I found one which optimize the query calls, faster the response with all accurate results.

i.e. you are creating an restaurant list app which requires the list which are only located within 10 Km or 10 miles from my current location.

I hope you already have configured your project with Firebase Firestore SDK.

Let’s start an implementation of Geo-Firestore library to get ready your code with creating and searching the nearest restaurants.

Adding a dependency into your gradle files

Now add below line into your build.gradle (project-level).

allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}

Then add the library to your build.gradle (app-level)

dependencies {
implementation 'com.github.chintan369:Geo-FireStore-Query:1.1.0'
}

Now you’ve added a dependency so waiting for what?, Click on “Sync Now”.

Before reading the list of the restaurants, we need to set location of the restaurant which is required and will help to find the required list. So set location first.

Setting a location of restaurant

val db = FirebaseFirestore.getInstance()

val document = db.collection("restaurants").document("punjabi")

document.set(data)
.addOnSuccessListener{ _ ->
//Set Location After your document created
document.setLocation(latitude, longitude, fieldName)
}
.addOnFailureListener { exception ->
//Document write failed
}

Here, we’ve created one restaurant with document named punjabi with the data you have provided. You must have to call setLocation() after created document successfully.

setLocation(latitude, longitude, fieldName, useUpdateMethod)

latitude and longitude (mandatory) — location points of restaurant
fieldName (optional) —
in which field name you want to store calculated point of location, if not passed then by default it will be stored in “g”
useUpdateMethod (optional) —
if you want to use update method or to use set method with merge options.

This will set two fields in your document
“g” (or your given fieldName) - Calculated degree match from given location point
“geoLocation” -
given location points in GeoPoint class

Now you’ve set location for restaurants. You can easily read the nearby list now.

Reading Nearby 10 Km restaurants from current location

You can read the data in two way as firestore provides in its native query.
Either Real-time snapshots or Single one-shot

Let’s create required objects for current location and distance in which we have to query.

val db = FirebaseFirestore.getInstance()

/*Create two object to pass location and distance for radius*/
val centerLocation = Location(centerLatitude, centerLongitude)
val distanceForRadius = Distance(10.0, DistanceUnit.KILOMETERS)
// or you can set unit as DistanceUnit.MILES

Here Location is the android’s Location class, and Distance class with 2 arguments 10.0 as radius and DistanceUnit.KILOMETERS or DisrtanceUnit.MILES as distance unit.
Now use this two objects to query the list.

Now create the GeoQuery class object to build the query as follow:

val geoQuery = GeoQuery()
.collection("restaurants")
.whereEqualTo("status","approved")
.whereEqualTo("country","IN")
.whereNearToLocation(centerLocation, distanceForRadius, fieldName)
.startAfter(lastDocument) //optinal (for pagination)
.limit(10) // If you requires only 10 data per query

whereNearToLocation(centerLocation, distanceForRadius, fieldName)
This function will be responsible to find the near-by list items where
centerLocation — object of current location from which near-by list is to be fetched
distanceForRadius object of distance with radius and distance unit
fieldName (optional) pass the same if you have passed in setLocation()’s fieldName

Let’s Go with Real-time snapshots first:

geoQuery.addSnapshotListener { firebaseFirestoreException, addedOrModifiedDataList, removedList  ->
...
//Do your stuff here
//If exception occurs, firebaseFirestoreException will not
be null else
//In addedOrModifiedDataList, you will get all data that
falls within distance and given query
as either ADDED for first time in query or has MODIFIED as
was in the query from first.
//In removedList, you will get data which is not relevent to
your query or out of distance
}

You can listen One-Shot data as:

geoQuery.get()
.addOnCompleteListener { firebaseFirestoreException, addedOrModifiedDataList, removedList ->
...
//Do your stuff here
}

OR

geoQuery.get()
.addOnSuccessListener { addedOrModifiedDataList, removedList ->
...
//Do your stuff here
}
.addOnFailureListener { exception ->
//If any exception occured
}

That’s all. You have implemented the Geo-Query in your firestore DB successfully with a single query read and faster response time.

Advantages Over Old Geo-Firestore Query

Old Geo-Firestore SDK for Android

  • Reducing the query calls from 3–4 query calls in a single query to just 1 query call
  • Faster response due to reducing query call
  • Accurate Data for the given radius of distance
  • Feel Code like Native Firestore Query implementation
  • Real-time and One-shot both supported in the query

Disadvantages due to firestore incapabilities

  • Can not be able to sort data on multiple fields as firestore not supporting multiple order-By sorting. So you can Either make pagination on geo-based value the filedName given by you (or can default) Or getting data all at once and sort it at your local level on the other filed which you want e.g. createdDateTime or any other

So What are you thinking now? Open your IDE and implement the same.

Also, Don’t forgot to claps for this article if you found it worthwhile.

--

--

Chintan Patel
Kotlindroid

Project Manager | Content Writer | Mentor | Senior Mobile App Developer | Enthusiastic | Energetic | Public Speaker