蔡濡安
蔡濡安

Reputation: 95

Returning reasonable data in vapor4

The main question is in func all. I want to get the Pers model when my distance is less than 100 meters(not include myself). I know that my return statement can't write in a for loop. But I don't actually know how to assign my filter.

controller:

    import Foundation
    import Vapor
    import Fluent
    import CoreLocation
    final class UserLocationController{
        func take (_ req: Request) throws -> HTTPStatus{
            let userlocation = try req.content.decode(UserLocation.self);
            let defalts = UserDefaults.standard
            defalts.setValue(userlocation.latitude, forKey: "latitude")
            defalts.setValue(userlocation.longitude, forKey: "longitude")
                return HTTPStatus.ok
        }
    func all (_ req: Request) throws ->EventLoopFuture<[Pers]>{
            let users = try req.content.decode([UserLocation].self)
            
            let latitude = UserDefaults.standard.double(forKey: "latitude")
            let longitude = UserDefaults.standard.double(forKey: "longitude")
            
            let userlocation = CLLocation(latitude: latitude, longitude: longitude)
            
            let newUsers = users.filter{ user in
                let location = CLLocation(latitude: user.latitude, longitude: user.longitude)
                return location.distance(from: userlocation) < 100
            }
            
            for value in newUsers{
                let user = value.user
                return Pers.query(on: req.db).filter(\.$user.$id == user).all()
            }
                    
        }
    }

UserLocation model:

import Foundation
import Vapor
import FluentPostgresDriver


struct UserLocation: Content{
    
    var id:UUID?
    
    var latitude: Double
    
    var longitude: Double
    
    var user: User.IDValue
    

}

Pers model:

import Foundation
import Fluent
import Vapor
import FluentPostgresDriver




final class Pers:Model,Content{
    static let schema = "pers"
    
    @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 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, 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.city=city
        self.hobby=hobby
        self.$user.id=userId
    }
}

Upvotes: 1

Views: 70

Answers (1)

0xTim
0xTim

Reputation: 5565

The short answer is that you can use the subset query to get all the users from a subset, e.g.

return Pers.query(on: req.db).filter(\.$user.$id ~~ newUsers.compactMap { $0.id }).all()

However there are a number of serious issues with your code. For starters if you're planning on deploying to Linux you cannot use CoreLocation. Second you're doing the location filter on the server instead of the database, so if you have a lot of users that query is going to be slow as you need to get every user from the database. A PostGIS query would be much more efficient.

Finally what are you trying to achieve with user defaults? They should not be used in server-side Swift. The way you have it is that the coordinates will be taken from whoever accessed the take endpoint last, even if it's not the same person accessing the all endpoint.

Upvotes: 2

Related Questions