0
votes

I am currently working on a firebase project. In this specific case we decided to use Firestore. For the sake of simplicity lets say we have multiple app users that post their location at a given time to the server so our document looks something like this

Footprint
-> username 
-> createdAt (timestamp in milliseconds)
-> location (Geopoint)

Now a user should be able to search all users around him this is pretty easy to do by using a Query like:

firestore.collection('footprint')
.where('location', isGreaterThan: bounds['lower'])
.where('location', isLessThan: bounds['upper'])

bounds['lower'] and bounds['upper'] contain 2 Geopoints.

Now this would work but it gives me all Data near a geopoint. But the user only cares about it in a Chronological order. More like who were the last 100 Persons near this location. So it seems bad to send 10.000 Datasets to a User just to order them on the client side. There is usually no Wi-Fi available.

So i wanted to paginate the result and tried the following:

firestore.collection('footprint')
.where('location', isGreaterThan: bounds['lower'])
.where('location', isLessThan: bounds['upper'])
.orderBy('createdAt')
.limit(25)

Doesnt Work, Firebase enforces to orderBy 'location' first in this case. But the result of

firestore.collection('footprint')
.where('location', isGreaterThan: bounds['lower'])
.where('location', isLessThan: bounds['upper'])
.orderBy('location')
.orderBy('createdAt')
.limit(25)

doesnt help me it would show a dataset from 2017 first if it is right next to my current location.

So I thought about alternative and found the following:

  1. Clustering the locations

I thought i could cluster the locations like mapping all locations from 17.13-17.17 to 17.15 and then i could use an equals Query to get the Data i want.

firestore.collection('footprint')
.where('location', isEqual: bounds['closest'])
.orderBy('createdAt')
.limit(25)

But now i got the problem what if the users wants everything in an 100 km radius i would than have to do a huge amout of queries. Think about using 5 km clusters it would be 40*40 queries for all clusters in a 100km radius. And even then i would have problem to limit this data, since i care for chronological order and i would still have to send about 10.000 Datasets to the user.

  1. Using an additional Date (or something similiar) Field

I have the feeling that this is the closest i came to find a real solution for my problem

Footprint
-> username 
-> createdAt (timestamp in milliseconds)
-> createdSearch (String looks like 2018-06-14)
-> location (Geopoint)

I could now Query the Data for a given Day like

firestore.collection('footprint')
.where('createdSearch',isEqual:'2018-06-14')
.where('location', isGreaterThan: bounds['lower'])
.where('location', isLessThan: bounds['upper'])
.orderBy('location')

This works but i would have to send additional queries for each day i want and i would have to order the data on the client side so no limit possible. If i have a lot of data i would also need to make my search field more explicit like '2018-06-14 12:00'. But then i would have to send a lot more queries ...

3 Trying to combine geopoint and timestamp into one Field

this should work in theorie, if i find a way to combine both values into one field that would allow to query them and order them with the same field this would work. But i have no idea how to do this.

I have the feeling that this should be a common problem , i found some other questions about Range Queries and ordering by other fields, but not with geolocations involved.

So what is the generell way to query for datasets near a given location and get them back by chronological order using Firestore ?

I should also mention that i dont want the user to wait for 30 Seconds so it should be a fast solution if possible. If other technologies(firebase) or data structures are necessary, that's ok too.

1

1 Answers

1
votes

The only "good" way if found to solve my problem was to use the last variation with firebase functions.

firestore.collection('footprint')
.where('createdSearch',isEqual:'2018-06-14')
.where('location', isGreaterThan: bounds['lower'])
.where('location', isLessThan: bounds['upper'])
.orderBy('location')

So the App makes a HTTPS Request to the firebase functions, the function loads everthing but does some server side filtering to reduce the amount of return values. Since this is not a real solution for my specific Question i wont mark it as answerd