David Henry
David Henry

Reputation: 3046

Filter Firebase Database based on location radius

I have the following Firebase Database structure,

"-KSupX7CppMD1zbqIy0y" : {
  "addedByUser" : "zQpb7o18VzYsSoTQtT9DNhOqTUn2",
  "content" : "Post 1",
  "cost" : "20",
  "duration" : "Weekly",
  "latitude" : "40.7594479995956",
  "longitude" : "-73.9838934062393",
  "timestamp" : "Fri 30 Sep"
},
"-KSuphuqO6a0lnrJYUkt" : {
  "addedByUser" : "zQpb7o18VzYsSoTQtT9DNhOqTUn2",
  "content" : "Post 2",
  "cost" : "10",
  "duration" : "Daily",
  "latitude" : "40.7594329996462",
  "longitude" : "-73.9846261181847",
  "timestamp" : "Fri 30 Sep"
}

I need to filter the posts within certain distance parameters (less than 50m, 100m, 150m & 200m) I can get the coordinate from the "longitude" & "latitude" but I'm struggling to filter the posts. Any help would be greatly appreciated.

Many thanks in advance. Newbie to Firebase & Swift.

Upvotes: 6

Views: 2873

Answers (3)

vp2698
vp2698

Reputation: 1805

Use GeoHash

Here is full documentation for it you can use single https://firebase.google.com/docs/firestore/solutions/geoqueries

Add this to your Podfile pod 'GeoFire/Utils'

Insert GeoHash

let latitude = 51.5074
let longitude = 0.12780
let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)

let hash = GFUtils.geoHash(forLocation: location)

// Add the hash and the lat/lng to the document. We will use the hash
// for queries and the lat/lng for distance comparisons.
let documentData: [String: Any] = [
    "geohash": hash,
    "lat": latitude,
    "lng": longitude
]

let londonRef = db.collection("cities").document("LON")
londonRef.updateData(documentData) { error in
    // ...
}

Get filter data

let queries = queryBounds.map { bound -> Query in
    return db.collection("cities")
        .order(by: "geohash")
        .start(at: [bound.startValue])
        .end(at: [bound.endValue])
}

Upvotes: 0

Dravidian
Dravidian

Reputation: 9945

For JSON like this:-

 UsersLocation :{
     autoID1 : {....},
     autoID2 : {.....}
           }

Try this:-

    FIRDatabase.database().reference().child("UsersLocation").queryOrdered(byChild: "lat").queryStarting(atValue: 30).queryEnding(atValue: 60).observeSingleEvent(of: .value, with: {(snap) in

        print(snap)


        if let snapDict = snap.value as? [String:AnyObject]{

            for each in snapDict{

                print(each)

            }
        }
    })
}

This will give you all the users with a autoID Key, with their latitude between 30 and 60, The order in which you retrieve data will be random, so to iterate through them in ascending order you can sort your dictionary that you receive .

Upvotes: 2

chickenparm
chickenparm

Reputation: 1620

Below is a solution you could try. This assumes you have all posts downloaded to the app from Firebase and stored in an array. You could also look into using GeoFire which I have not personally used (But would like to). I believe it allows you to query Firebase by location so you do not first have to download all posts to a user's device and filter on the client side.

// assumes you have set up the app to get the user's current location
var currentLocation: CLLocation?

// Your array of posts downloaded from Firebase
var postArray = [post]()

let metersInTwentyFiveMiles = 40233.6

// You could put this in viewDidAppear after you load the post array from Firebase
for post in postArray {

    var distanceInMeters: CLLocationDistance = 0

    let postLocation = CLLocation(latitude: post.latitude, longitude: post.longitude)


    if let currentLocation = self.currentLocation {
         // Set distanceInMeters to the distance between the user's current location and the location of the post.
         distanceInMeters = currentLocation.distanceFromLocation(postLocation)
         // If this distance is not within 25 miles, remove this post from the array
         if self.metersInTwentyFiveMiles < distanceInMeters {
            self.posts = self.posts.filter{ $0 != post }
       }
    }
}

Upvotes: 0

Related Questions