按用户位置与 Firebase 附近的距离对数组进行排序

Posted

技术标签:

【中文标题】按用户位置与 Firebase 附近的距离对数组进行排序【英文标题】:Sort array by distance near user location from firebase 【发布时间】:2017-11-18 10:27:54 【问题描述】:

不知道如何在用户附近自动对地址进行排序。我不明白从哪里开始以及如何编写代码。

我的 firebase 中有地址。地址具有字符串类型(不是纬度/经度)。示例:

"Москва, Электрозаводская, 21"
"Москва, Арбат, Староконюшенный переулок, дом 43"
"Москва, улица 1-я Бухвостова, дом 12/11, корпус 53"

我知道需要使用 firebase 中的 query,但是如何使用 query,我现在不明白。

这是我的代码:

class PhotoStudiosViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate 

    @IBOutlet weak var tableView: UITableView!

    var theStudios: [Studio] = []

    var studiosRef: DatabaseReference!

    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(true)

        tableView.estimatedRowHeight = 475
        tableView.rowHeight = UITableViewAutomaticDimension

        loadDataFromFirebase()

    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

        return theStudios.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! PhotoStudiosTableViewCell

        cell.addressLabel.text = theStudios[indexPath.row].studioAddress

        return cell
    

    func loadDataFromFirebase() 

        studiosRef = Database.database().reference(withPath: "Addresses")

        let time = DispatchTime.now() + 0.5 

        studiosRef.observe(.value, with:  (snapshot) in

        DispatchQueue.main.asyncAfter(deadline: time) 

            for imageSnap in snapshot.children 

                let studioObj = Studio(snapshot: imageSnap as! DataSnapshot)

                self.theStudios.append(studioObj)

            

            self.tableView.reloadData()

        

    )





class Studio 

    var ref: DatabaseReference! 
    var studioAddress: String = ""

    init(snapshot: DataSnapshot) 

        ref = snapshot.ref
        studioName = snapshot.key

        let value = snapshot.value as! NSDictionary 

        studioAddress = value["address"] as? String ?? "---"

    

如何使用来自 firebase 的数据对用户附近的地址进行自动排序

【问题讨论】:

【参考方案1】:

这是一个复杂的过程,需要多个步骤。我将尝试解释这些步骤,但您必须做很多工作才能将其转化为有效的解决方案。

地理编码

首先:像您所拥有的地址字符串不是位置。计算机无法比较两个这样的字符串并可靠地知道它们之间的距离。

因此,您要做的第一件事就是将地址转换为更可靠的位置指示,即转换为纬度和经度(也称为纬度/经度)。将地址转换为纬度/经度的过程称为geocoding。这并不是一门真正的精确科学,但有很多服务非常擅长这个地理编码位。

在此地理编码过程结束时,您将获得每个地址的纬度/经度组合。这让问题回到了数学,这是一门更精确的科学。

地理查询

接下来,您需要比较每个地址和calculate the distance between them 的纬度/经度。这一门相对精确的科学,如果您愿意忽略两极附近的不准确之处或类似情况。

不幸的是,Firebase 实时数据库本身只能对单个属性进行排序/过滤。由于一个位置包含两个属性(纬度和经度),因此如果没有一些魔法,它就无法过滤位置。

幸运的是,有人想出了一种将纬度/经度信息转换为单个字符串的方法,称为geohash。例如:Google office in San Francisco 位于纬度/经度 37.7900515,-122.3923805,转换为 geohash 9q8yyz。 Mountain View 中的 Googleplex 位于纬度/经度 37.4219999,-122.0862515,转换为 geohash 9q9hvu

与您开始使用的地址不同,geohashes 具有很好的可比性。引用(链接的)***解释:

附近的地方[有]相似的前缀。共享前缀越长,两个地方越接近。

在我们上面的两个示例中,您可以看到这两个位置相对靠近,因为它们都以9q 开头

有一个名为 GeoFire 的 Firebase 开源库:

    可以轻松地将位置(您必须具有纬度/经度)存储在 Firebase 中作为 geohashes。 提供查询功能,以便您可以获取位于您指定位置最大距离内的节点。

我建议您查看iOS version of GeoFire。

【讨论】:

根据您链接的***文章,“两点可能非常接近,但有一个短或没有共享前缀”。哈希比较不能保证找到所有位置。 正确。这就是为什么 GeoFire(和其他地理查询库)最多运行 9 个查询,中心周围的每个扇区一个。

以上是关于按用户位置与 Firebase 附近的距离对数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章

将 Firebase 查询与 GeoQuery 相结合,按名称搜索附近区域的帖子

如何比较两个位置

如何让用户在我在 geofire、Firebase 的位置附近

查询附近的位置

计算两个地理位置之间的距离

Swift如何按距离对表格视图进行排序