一旦坐标在 Firebase 中保存为字符串,如何在 CLLLoationDegrees 中获取它们来计算用户之间的距离?

Posted

技术标签:

【中文标题】一旦坐标在 Firebase 中保存为字符串,如何在 CLLLoationDegrees 中获取它们来计算用户之间的距离?【英文标题】:Once coordinates are saved as String in Firebase, how are they fetched in CLLLoationDegrees to calculate the distance between users? 【发布时间】:2019-07-09 09:09:44 【问题描述】:

我认为应该这样做:

1 在 Firebase 中创建所有用户坐标经度和纬度条目的快照 - 在输出框中打印出来以检查此步骤。

2.1 命名一个函数,用于计算登录用户与所有其他用户之间的距离

2.2 在该函数中 make let coordinate₀ = 登录用户的坐标。数据库具有坐标的字符串值,因此需要以某种方式将其设置为 CLLLoationDegrees。

2.3 为坐标1创建一个循环,直到坐标X(即数据库中的所有用户)为其坐标

2.4 使用 let distanceInMeters = coordinate₀.distance(from: coordinate₁) 并循环所有距离,直到坐标X(数据库中的最后一个)

2.5 打印输出框中的所有距离。 (我不需要将它们打印在应用程序上,我只是获取距离,以便按距离对用户进行排名)

The Database looks like this for each kid:
   "people" : 
    "2jWm6rUfZVYAGkSST0fvVvwolY92" : 
      "Coordinates" : 
        "latitude" : 45.785834,
        "longitude" : -100.406417
      ,
      "Education" : "BA Arts",
      "PhotoPosts" : "https://firebasestorage.googleapis.com/v0/b/westpluto1.appspot.com/o/images%2FPhotoPosts?alt=media&token=ccd5a139-b3e1-4ac9-965c-2f09c149fc74",
      "users" : "jackmaster1091@aol.com"
    ,


///Part A
  var refArtists : DatabaseReference!
var people = [Userx]()
var latestLocation: [String: Double]?   ////this double was added to get coordinates into firebase under longitude and latitude

///B部分

   let thisUsersUid = Auth.auth().currentUser?.uid //Mr. Dunn's uid
refArtists = Database.database().reference().child("people");

refArtists.observe(DataEventType.value,  with: snapshot in
if snapshot.childrenCount>0
self.people.removeAll()
   for people in snapshot.children.allObjects as! [DataSnapshot] 
   if people.key != thisUsersUid  //do not add this users info to the array
   let peopleObject = people.value as? [String: AnyObject]
   let peopleCoordinates = peopleObject?["Coordinates"]  as? String
   let peopl = Userx(Coordinates: peopleCoordinates)
   self.people.append(peopl)  
        
        self.table.reloadData()
        print(snapshot)
        
    

)

///C部分

func distance ()
    let databaseRef = Database.database().reference()
    let uid = Auth.auth().currentUser!.uid
    let coordinate₀ = CLLocation(latitude: databaseRef.child("people").child(uid).child("Coordinates").child("latitude"), longitude: databaseRef.child("people").child(uid).child("Coordinates").child("longitude")) //////I think this is incorrect even w/o string to CLL conversion because I don’t think longitude and latitude and technically children of Coordinates
        …..
        let distanceInMeters = coordinate₀.distance(from: coordinate₁)
        let distanceInMeters2 = coordinate₀.distance(from: coordinate2)
        ….
Print …
Print …

///////代码基于 Jay 的回答

 let uid = Auth.auth().currentUser!.uid

    let ref = Database.database().reference().child("people").child(uid).child("Coordinates")

ref.observeSingleEvent(of: .value, with:  snapshot in
    let allCoordinates = snapshot.children.allObjects as! [DataSnapshot]
    for Coordinates in allCoordinates 
        let lat = Coordinates.childSnapshot(forPath: "latitude").value as! CLLocationDegrees
        let lon = Coordinates.childSnapshot(forPath: "longitude").value as! CLLocationDegrees
        let userId = Coordinates.key
        let locCoord = CLLocationCoordinate2DMake(lat, lon)
        let bcoordinates  = CLLocationCoordinate2D(latitude: lat, longitude: lon)
    
)

///第二次更新代码:

    let uid = Auth.auth().currentUser!.uid

refArtists = Database.database().reference().child("people");

let ref = self.refArtists.child(uid).child("Coordinates")


ref.observeSingleEvent(of: .value, with:  snapshot in
    let allLocations = snapshot.children.allObjects as! [DataSnapshot]
    for location in allLocations 
        let userId = location.key
        let coordSnap = location.childSnapshot(forPath: "Coordinates")
        let lat = coordSnap.childSnapshot(forPath: "latitude").value as! CLLocationDegrees
        let lon = coordSnap.childSnapshot(forPath: "longitude").value as! CLLocationDegrees
        let locCoord = CLLocationCoordinate2DMake(lat, lon)
        let coordinates  = CLLocationCoordinate2D(latitude: lat, longitude: lon)
        print("   coords: \(lat)  \(lon)")
    
)

////这是现在打印两个坐标的代码:

let ref = self.refArtists.child(uid).child("Coordinates")
ref.observeSingleEvent(of: .value, with:  snapshot in
    let allLocations = snapshot.children.allObjects as! [DataSnapshot]
    for location in allLocations 
        let userId = location.key
        let lat = snapshot.childSnapshot(forPath: "latitude").value as! CLLocationDegrees
        let lon = snapshot.childSnapshot(forPath: "longitude").value as! CLLocationDegrees
        let locCoord = CLLocationCoordinate2DMake(lat, lon)
        let coordinates  = CLLocationCoordinate2D(latitude: lat, longitude: lon)
        print("   coords: \(lat)  \(lon)")
    

我希望在这一切之后根据位置对用户进行排名。

【问题讨论】:

CLLocationDegrees 可能应该存储为双精度,然后您可以读取它们并像这样直接分配它们`let coord = CLLocationCoordinate2DMake(lat, lon)'。有关工作代码,请参阅this question 的答案。我不明白问题的其余部分在问什么。 谢谢。是的,它存储为双精度数。您链接的代码有意义但给出错误:“任何?”不能转换为 '[String : AnyObject]';你的意思是用'as!'强制向下转换?”你知道如何解决这个问题吗?我认为这是 Xcode 版本类型的错误。我当然将“位置”更改为我在 firebase 中设置的内容。 是的 - 此时问题中的代码已经使用了三年,并且没有针对 swift 5 进行更新。我发布了一个答案,让您朝着正确的方向前进。 谢谢!我会试试的。 【参考方案1】:

有多种方法可以读取您询问的数据。以下是每个的摘要

选项 1)

如果有一系列节点直接在节点内存储坐标数据

people
   uid_0
      Latitude: xxxxxxxx
      Longitude: yyyyyyy
   uid_1
      Latitude: aaaaaaaa
      Longitude: bbbbbbbb

并且您想遍历每个节点并为每个位置节点(loc_0、loc_1 或 uid_0 uid_1 等)创建一个 CoreLocation 对象,这是执行此操作的代码。

let ref = self.ref.child("people")
ref.observeSingleEvent(of: .value, with:  snapshot in
    let allUsers = snapshot.children.allObjects as! [DataSnapshot]
    for user in allUsers 
        let lat = user.childSnapshot(forPath: "Latitude").value as! CLLocationDegrees
        let lon = user.childSnapshot(forPath: "Longitude").value as! CLLocationDegrees
        let userId = user.key
        let locCoord = CLLocationCoordinate2DMake(lat, lon)
        let coordinates  = CLLocationCoordinate2D(latitude: lat, longitude: lon)
    
)

注意 self.ref 指向我的 Firebase 根目录。

选项 2)

如果您的 Firebase 结构的坐标数据存储在每个父节点下的 Coordinates 节点中,则将 Coordinates 节点视为它自己的快照,这样您就可以访问它的两个子坐标,lat 和 lon。

people
   uid_0
      name: "some user"
      coordinates:
         Latitude: 1
         Longitude: 2
   uid_1
      name: "another user"
      coordinates:
         Latitude: 3
         Longitude: 4

请注意,我添加了一个名称子节点,因此您也可以查看如何读取它。

let ref = self.ref.child("people")
ref.observeSingleEvent(of: .value, with:  snapshot in
    let allUsers = snapshot.children.allObjects as! [DataSnapshot]
    for user in allUsers 
        let userName = user.childSnapshot(forPath: "name").value as! String
        let userId = user.key
        let coordSnap = user.childSnapshot(forPath: "coordinates")
        let lat = coordSnap.childSnapshot(forPath: "Latitude").value as! CLLocationDegrees
        let lon = coordSnap.childSnapshot(forPath: "Longitude").value as! CLLocationDegrees
        let locCoord = CLLocationCoordinate2DMake(lat, lon)
        let coordinates  = CLLocationCoordinate2D(latitude: lat, longitude: lon)
        print("uid: \(userId)  name: \(userName)")
        print("   coords: \(lat)  \(lon)")
    
)

输出将如下所示

uid: uid_0  name: some name
   coords: 1.0  2.0
uid: uid_1  name: another name
   coords: 3.0  4.0

选项 3)

如果您想读取单个特定节点而不是遍历所有节点,代码如下。您需要知道父节点的路径,在这种情况下是当前用户的 uid。

func readThisUsersCoordinates() 
    let uid = Auth.auth().currentUser!.uid
    let peopleRef = Database.database().reference().child("people");
    let thisPersonRef = peopleRef.child(uid)
    let thisPersonCoordsRef = thisPersonRef.child("Coordinates")
    thisPersonCoordsRef.observeSingleEvent(of: .value, with:  snapshot in
        let lat = snapshot.childSnapshot(forPath: "latitude").value as! CLLocationDegrees
        let lon = snapshot.childSnapshot(forPath: "longitude").value as! CLLocationDegrees
        print("   coords: \(lat)  \(lon)")
    )

【讨论】:

谢谢。我的数据库看起来有点不同。我试图调整代码以适应我的数据库的外观,但我得到 Thread 1: signal SIGABRT 错误,所以它没有找到孩子。你看到我没有看到的任何错误吗?我的数据库如下所示: People Random User ID Code DataPoin 1: DataPoin 2 : Coordinates + latitude: ...... longitude: ..... Random User ID Code2 ........问题,因为这里太长了: 5 分钟评论限制刚刚达到。问题中的数据库结构比评论中的更清晰。 @noname87f 您需要将坐标节点作为子快照读取。我更新了我的问题来解决这个问题。 非常感谢。我很感激你的时间。我的数据库中没有“名称”路径,所以我删除了它。我仍然在 let lat = ... 行出现错误。但是,上一行 let coordSnap 可以工作,所以 this 的形式是正确的。我不知道这是否是因为纬度和经度不是坐标的正常孩子,而是它的双重列表。您对为什么会出现错误有任何想法吗?我已经在问题中添加了我现在使用的代码。 @noname87f 我将该代码从一个有效的现有项目中取出。我的猜测是您没有指定正确的子密钥名称。我的结构包括子键Latitude,因此我的代码访问了子键Latitude。您的结构包括latitude(小写L),所以这是您应该访问的孩子。我的代码匹配 my 结构,因此您可能需要匹配 your 结构。我添加了阅读 name 节点作为模板,以便您了解如何访问其他子节点。有意义吗?

以上是关于一旦坐标在 Firebase 中保存为字符串,如何在 CLLLoationDegrees 中获取它们来计算用户之间的距离?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有 Geofire 的情况下将位置对象保存在 Firebase 中?

是否可以将一组坐标保存到firebase?

Firebase Firestore 保存地标与仅坐标

如何将查询中的数据保存在字符串数组中,Firebase iOS?

是否可以在 Android Studio 中使用 Firebase 数据库添加子代同时保留旧代?

如何将数据保存在firebase父键中不是默认值