3

I'm using GeoFire and trying to fetch only 3 results that satisfy some conditions. This it my case and it doesn't stop observer. There are several thousands results and I get it all but I need only 3. I based on this answer but it does't work in my case as you can see. Please can somebody help?

var newRefHandle: FIRDatabaseHandle?
var gFCircleQuery: GFCircleQuery?

func findFUsersInOnePath(location: CLLocation,
                         radius: Int,
                         indexPath: String,
                         completion: @escaping () -> ()){
    var ids = 0
    let geofireRef = usersRef.child(indexPath)
    if let geoFire = GeoFire(firebaseRef: geofireRef) {
        gFCircleQuery = geoFire.query(at: location, withRadius: Double(radius))
        newRefHandle = gFCircleQuery?.observe(.keyEntered, with: { (key, location) in
            // if key fit some condition
            ids += 1
            if (ids >= 3) {
                self.gFCircleQuery?.removeObserver(withFirebaseHandle: self.newRefHandle!)
                completion()
            }
        })
        
        gFCircleQuery?.observeReady({
            completion()
        })
}

Please, never mind on Optionals(?) it is just for this example code

From GoeFire documentation:

To cancel one or all callbacks for a geo query, call removeObserverWithFirebaseHandle: or removeAllObservers:, respectively.

Both are not working.

Community
  • 1
  • 1
Yura Buyaroff
  • 1,718
  • 3
  • 18
  • 31

1 Answers1

1

Geofire under the hoods fires a Firebase Database query. All results are retrieved from Firebase in one go and then locally it fires the keyEntered event for each of them (or .childAdded for the regular SDK).

Calling removeObserver(withFirebaseHandle: will stop Geofire from retrieving additional results. But it will still fire keyEntered for any results that have already been retrieved.

The solution is to add an additional condition to ignore those already retrieved results:

   newRefHandle = gFCircleQuery?.observe(.keyEntered, with: { (key, location) in
     if (id <= 3) {
        // if key fit some condition
        ids += 1
        if (ids >= 3) {
            self.gFCircleQuery?.removeObserver(withFirebaseHandle: self.newRefHandle!)
            completion()
        }
      }
    })
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks! Does it mean I will anyway pay for downloading all thousands of objects each time I want to get 1-3 results? – Yura Buyaroff Jul 19 '17 at 03:28
  • 2
    You will pay for downloading any items that are in your range. If you want the minimum range that contains a certain number of keys, this approach is not ideal. The order in which the keys fire is not based on proximity to the center of the query, but from one of the corners of the query's range. You're likely better off starting with a query with a small range, and then firing another geo query with a broader range if you didn't get enough results. – Frank van Puffelen Jul 19 '17 at 03:48
  • I see. Thank you very much. – Yura Buyaroff Jul 19 '17 at 03:50