I'm now trying to input a
longitude
and latitude
and return a Pers
model if the distance is under (any number) meters. And I know CLLocation
is a bad usage in here, but it didn't came up with any idea with postgis
. So in this condition, what do I have is a controller down below, and I think I should code something in the return filter. But I don't actually know what to do inside the filter to make the compile pass.
Controller :
import Foundation
import Vapor
import Fluent
import CoreLocation
final class InformationController{
func temp(_ req:Request) throws -> EventLoopFuture<[Pers]> {
let userlocation = try req.content.decode(Pers.UserLocation.self)
let mylocation = CLLocation(latitude: userlocation.latitude, longitude: userlocation.lonitude)
let pers = try req.content.decode([Pers].self)
let newUsers = pers.filter{ user in
let location = CLLocation(latitude: user.latitude, longitude: user.longitude)
return location.distance(from: mylocation) < 100
}
return Pers.query(on: req.db).filter().all()
}
}
Pers
model :
import Foundation
import Fluent
import Vapor
import FluentPostgresDriver
final class Pers:Model,Content{
static let schema = "people"
@ID(key: .id)
var id:UUID?
@Field(key: "姓名")
var name: String
@Field(key: "IG帳號")
var account: String
@Field(key: "頭像")
var picture: String
@Field(key: "年紀")
var age: String
@Field(key: "生日")
var birth: String
@Field(key:"緯度")
var latitude: Double
@Field(key:"經度")
var longitude: Double
@Field(key: "居住城市")
var city: String
@Field(key: "興趣")
var hobby : String
@Parent(key: "user_id")
var user: User
init(){}
init(id:UUID?=nil, name:String, account:String, picture:String ,age:String, birth:String,latitude: Double, longitude: Double, city:String, hobby:String, userId:UUID){
self.id=id
self.name=name
self.account=account
self.picture=picture
self.age=age
self.birth=birth
self.latitude = latitude
self.longitude = longitude
self.city=city
self.hobby=hobby
self.$user.id=userId
}
}
extension Pers{
struct UserLocation: Content {
var latitude: Double
var lonitude: Double
}
}
The answer to your immediate question is to just return newUsers
, changing the return type of your route as shown, but I would also decode using something like:
struct LocData: Decodable {
let userLocation: Pers.UserLocation
let pers: [Pers]
}
func temp(_ req:Request) throws -> [Pers] {
let locData = try req.content.decode(LocData.self)
let userlocation = locData.userLocation
let mylocation = CLLocation(latitude: userlocation.latitude, longitude: userlocation.longitude)
return locData.pers.filter{ user in
let location = CLLocation(latitude: user.latitude, longitude: user.longitude)
return location.distance(from: mylocation) < 100
}
}
Your JSON needs to look something like:
{ "userLocation" : { ... },
"pers" : [ ... ]
}
Your subsequent problem is you are trying to decode the request data two different ways. The first one works but the second one fails. You were only supplying JSON data for the first decode in your example image, so there was no array for the second decode.
The more fundamental issue is that you should really be doing this operation client-side, given that you must have all the source data you need in order to send it to the server. It doesn't make sense to transfer a potentially large dataset to do a simple, self-contained calculation only to return (a subset of) the same dataset as a response. See How to find my distance to a known location in JavaScript for an example implementation of the required calculation.