英文:
Swift Vapor query filtering and sorting by distance
问题
我正在开发Swift Vapor项目。我需要按照距离筛选和排序用户(距离不应超过100公里,最近的用户应该排在最前面)。我有纬度和经度的坐标。我需要使用查询方法中的filter和sort来实现优化。我该如何做?
我正在使用PostgreSQL数据库。
func getAll(_ req: Request, arguments: UserFilter) async throws -> [User] {
let user = try req.auth.require(User.self)
var query = User.query(on: req.db)
arguments.filter(&query)
if let lat = user.latitude, let lon = user.longitude {
query.filter(
User.self,
field: \.latitude, // 提供字段的KeyPath
method: .lessThanOrEqual, // 提供过滤方法
value: lat + 0.1 // 提供值
)
// 在此处添加排序逻辑,根据距离排序
// 请注意,需要计算距离并将其添加到查询中
}
return try await query.all()
}
@OptionalField(key: "latitude")
var latitude: Float?
@OptionalField(key: "longitude")
var longitude: Float?
请注意,上面的代码示例中,我添加了如何过滤纬度字段的示例。你需要根据提供的经度和距离值来计算并添加排序逻辑,以确保最接近的用户排在最前面。
英文:
I'm working on the swift vapor project. I need to filter and sort users by distance(it should not exceed 100 kilometers and the first user should be the closest). I have the coordinates latitude and longitude. I need to do this specifically with query methods filter and sort for good optimization. How can I do this?
I'm using PostgreSQL db.
func getAll(_ req: Request, arguments: UserFilter) async throws -> [User] {
let user = try req.auth.require(User.self)
var query = User.query(on: req.db)
arguments. filter(&query)
if let lat = user.latitude, let lon = user.longtitude {
query. filter(
User.self,
field: KeyPath<Schema, QueryableProperty>, // not yet provided
method: DatabaseQuery.Filter.Method, // not yet provided
value: Decodable & Encodable) // not yet provided
)
}
}
return try await query.all()
@OptionalField(key: "latitude")
var latitude: Float?
@OptionalField(key: "longtitude")
var longtitude: Float?
答案1
得分: 1
我不确定你是否能直接使用ORM来实现这个,如果你想保留Float
的话。如果你想使用ORM,我建议你使用https://github.com/brokenhandsio/fluent-postgis 这个库。
如果你想保留Float
,你可以使用两种方法来应用勾股定理:
- 切换到原始SQL:
let query = """
SELECT * FROM your_table
ORDER BY SQRT(POW(111.1 * (latitude - \(bind: lat)), 2) +
POW(111.1 * (longitude - \(bind: lon)) * COS(latitude / 57.3), 2))
"""
- 在查询之后对它们进行排序
.map { models in
return models.sorted { model1, model2 in
let distance1 = sqrt(pow(111.1 * (model1.latitude - lat), 2) +
pow(111.1 * (model1.longitude - lat) * cos(model1.latitude / 57.3), 2))
let distance2 = sqrt(pow(111.1 * (model2.latitude - lat), 2) +
pow(111.1 * (model2.longitude - lon) * cos(model2.latitude / 57.3), 2))
return distance1 < distance2
}
}
其中:
- 111.1是每纬度公里数的近似值(如果使用英里,改为69.1)
(latitude - \(lat))
计算纬度差异COS(latitude / 57.3)
是调整经度差异以适应地球曲率的近似值。57.3是一个弧度中的度数的近似值(180/π),因此这将纬度从度转换为弧度(longitude - \(lon))
计算经度差异
请注意,这个定理是对距离的近似值,所以在长距离上可能不是特别精确!
英文:
I'm not sure you are able to do this directly using the ORM if you're keen on keeping Float
s. If you want to use the ORM I'd say your best bet is https://github.com/brokenhandsio/fluent-postgis
If you want to keep Float
s you can use the Pythagorean Theorem in two manners:
- Drop down do raw SQL:
let query = """
SELECT * FROM your_table
ORDER BY SQRT(POW(111.1 * (latitude - \(bind: lat)), 2) +
POW(111.1 * (longitude - \(bind: lon)) * COS(latitude / 57.3), 2))
"""
- Sort them after querying
.map { models in
return models.sorted { model1, model2 in
let distance1 = sqrt(pow(111.1 * (model1.latitude - lat), 2) +
pow(111.1 * (model1.longitude - lat) * cos(model1.latitude / 57.3), 2))
let distance2 = sqrt(pow(111.1 * (model2.latitude - lat), 2) +
pow(111.1 * (model2.longitude - lon) * cos(model2.latitude / 57.3), 2))
return distance1 < distance2
}
Where:
- 111.1 is an approximation of the number of Kms per degree of latitude. (change to 69.1 if you're using miles)
(latitude - \(lat))
calculates the difference in latitudesCOS(latitude / 57.3)
is an approximation to adjust the longitude difference for the curvature of the Earth. 57.3 is approximately the number of degrees in one radian (180/π), so this is converting the latitude from degrees to radians(longitude - \(lon))
calculates the difference in longitudes
Be aware that this theorem is approximating the distance so at long distances it might not be particularly precise!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论