You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift中如何计算Firestore两个不同集合的经纬度距离

在iOS Swift中计算Firestore两个集合的经纬度距离

首先得明确两个核心环节:从Firestore拉取对应数据,以及计算两组经纬度间的实际距离。下面我一步步给你拆解实现逻辑:

1. 导入必要框架

先确保你已经集成了Firebase和CoreLocation(用系统自带的距离计算API会更省心),在Swift文件顶部添加:

import FirebaseFirestore
import CoreLocation

2. 获取Current_booking的起点经纬度

首先得拿到订单的起点坐标,假设你知道目标订单的文档ID,或者需要查询特定条件的订单:

func fetchBookingStartLocation(bookingDocID: String, completion: @escaping (CLLocationCoordinate2D?) -> Void) {
    let db = Firestore.firestore()
    db.collection("Current_booking").document(bookingDocID).getDocument { snapshot, error in
        guard let doc = snapshot, doc.exists,
              let startLat = doc["Start_lat"] as? Double,
              let startLong = doc["Start_long"] as? Double else {
            print("获取起点失败:\(error?.localizedDescription ?? "未知错误")")
            completion(nil)
            return
        }
        let startCoord = CLLocationCoordinate2D(latitude: startLat, longitude: startLong)
        completion(startCoord)
    }
}

3. 获取目标区域司机数据并计算距离

根据业务需求(比如用户所在的城市、街道区域),从Driver_details的层级结构中拉取司机坐标,再逐个计算到起点的距离:

func calculateDriversToStartDistance(startCoord: CLLocationCoordinate2D, city: String, area: String) {
    let db = Firestore.firestore()
    // 对应Driver_details -> 城市 -> 街道区域的集合路径
    let driversCollection = db.collection("Driver_details").document(city).collection(area)
    
    driversCollection.getDocuments { snapshot, error in
        guard let driverDocs = snapshot?.documents, error == nil else {
            print("获取司机数据失败:\(error?.localizedDescription ?? "未知错误")")
            return
        }
        
        let startLocation = CLLocation(latitude: startCoord.latitude, longitude: startCoord.longitude)
        
        for driverDoc in driverDocs {
            guard let driverLat = driverDoc["lat"] as? Double,
                  let driverLong = driverDoc["long"] as? Double,
                  let driverName = driverDoc["name"] as? String else {
                continue
            }
            
            let driverLocation = CLLocation(latitude: driverLat, longitude: driverLong)
            // 计算距离,单位是米,转公里的话除以1000即可
            let distanceInMeters = startLocation.distance(from: driverLocation)
            let distanceInKm = distanceInMeters / 1000
            
            print("司机\(driverName)到起点的距离:\(String(format: "%.2f", distanceInKm))公里")
        }
    }
}

4. 组合调用流程

把上面两个方法结合起来,处理异步数据的加载顺序:

func startDistanceCalculation(targetCity: String, targetArea: String, targetBookingID: String) {
    fetchBookingStartLocation(bookingDocID: targetBookingID) { startCoord in
        guard let coord = startCoord else { return }
        self.calculateDriversToStartDistance(startCoord: coord, city: targetCity, area: targetArea)
    }
}

// 调用示例:查询班加罗尔st.thomas区域的司机到某订单的距离
startDistanceCalculation(targetCity: "班加罗尔", targetArea: "st.thomas", targetBookingID: "YOUR_BOOKING_DOC_ID")

备选:手动实现Haversine公式(无需CoreLocation)

如果不想依赖CoreLocation框架,可以自己实现球面距离计算的Haversine公式:

func haversineDistance(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> Double {
    let earthRadiusKm = 6371.0 // 地球平均半径(公里)
    let dLat = (lat2 - lat1).toRadians()
    let dLon = (lon2 - lon1).toRadians()
    
    let a = sin(dLat/2) * sin(dLat/2) +
            cos(lat1.toRadians()) * cos(lat2.toRadians()) *
            sin(dLon/2) * sin(dLon/2)
    let c = 2 * atan2(sqrt(a), sqrt(1 - a))
    
    return earthRadiusKm * c
}

// 给Double添加弧度转换扩展
extension Double {
    func toRadians() -> Double {
        return self * .pi / 180.0
    }
}

使用时替换之前的距离计算代码即可:

let distance = haversineDistance(lat1: startCoord.latitude, 
                                 lon1: startCoord.longitude, 
                                 lat2: driverLat, 
                                 lon2: driverLong)
print("司机\(driverName)到起点的距离:\(String(format: "%.2f", distance))公里")

关键注意事项

  • Firestore查询是异步的,务必用completion handler或Swift 5.5+的async/await处理数据加载顺序,避免空值问题。
  • 如果司机数据量很大,建议在Firestore端做地理过滤查询(比如只拉取起点周边X公里内的司机),而不是全量拉取到客户端计算——Firestore支持基于GeoPoint的地理空间查询,能大幅提升性能和节省带宽。
  • 确认Firestore安全规则允许读取这两个集合,避免因权限问题导致数据拉取失败。

内容的提问来源于stack exchange,提问作者PvDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:34:10