Search code examples
swiftfirebasegoogle-cloud-firestoregeofire

Can't get near Users by my location with Firebase (GeoFire) and Swift


I want to get all Users near by my own Location.

I wrote following code in the location Manager didUpdateLocation function.

First I grabbed my own location as a CCLocationCoridnate2D.
if let location = locations.last{ let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)

Than I made a query to get all users near by my location.

let geofireRef = Database.database().reference()
                let geoFire = GeoFire(firebaseRef: geofireRef)
            
            
            
            
            
            geoFire.setLocation(CLLocation(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), forKey: "test")
          
         
            let centerQuery = CLLocation(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
            let circleQuery = geoFire.query(at: centerQuery, withRadius: 5)

            var queryHandle = circleQuery.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
               print("Key '\(key)' entered the search area and is at location '\(location)'")
                
                
                
            })

If I now want to replace "test" with my actual user (userdocid) it won't work.

How I grab my User:

Firestore.firestore().collection("users").whereField("uid", isEqualTo: Auth.auth().currentUser?.uid ?? "x")
                            .getDocuments { (querySnapshot, err) in
                                if err != nil {
                                    print("Failed")
                                    return
                                }
let  userdocid = querySnapshot!.documents[0].documentID

The App is crashing because of empty NSArray.

Thank you in advance Mark


Solution

  • This answer depends on how you're user data is stored but if you're storing users with their documentId as the users uid then just

    let uid = Auth.auth().currentUser!.uid //should safe unwrap that optional
    

    then

    geoFire.setLocation(CLLocation(..., forKey: uid)
    

    however, if you want to get it as you're doing in the question

    let uid = Auth.auth().currentUser!.uid
    let usersCollection = Firestore.firestore().collection("users")
                                   .whereField("uid", isEqualTo: uid)
                            
    usersCollection.getDocument(completion: { documentSnapshot, error in
        if let err = error {
             print(err.localizedDescription)
             return
         }
    
         guard let docs = documentSnapshot?.documents else { return }
    
         let thisUserUid = docs[0].documentID
         print(thisUserUid)
    })
    

    But again, that's a bit redundant as it wound indicate storing the uid in both the documentId as well as a child field, which is unnecessary:

    users
      uid_0 //the documentId
         name: "Users name"
         uid: "uid_0" //not needed
    

    The problem appers to be actually getting the center point - e.g. if it's not stored, then when read, it will be empty and you'll get that error.

    So you have to store it to start with

    geoFire.setLocation(CLLocation(latitude: 37.7853889, longitude: -122.4056973), forKey: uid) { (error) in
      if (error != nil) {
        print("An error occured: \(error)")
      } else {
        print("Saved location successfully!")
      }
    }
    

    Once you successfully stored a center point (your location), and then retrieved it, then the actual query should be

    let center = CLLocation(userLocation)
    geoFire.queryAtLocation(center, withRadius: 20);
    

    Oh, and a very important thing is the setLocation is asynchronous; it takes time for the server to store the data. You should really be working with the data within the closure

    geoFire.setLocation(CLLocation(latitude: 37.7853889, longitude: -122.4056973), forKey: uid) { (error) in
       // data is now valid so perform your query
    }