Vapor 3 和 Fluent - 嵌套查询

Posted

技术标签:

【中文标题】Vapor 3 和 Fluent - 嵌套查询【英文标题】:Vapor 3 and Fluent - nested query 【发布时间】:2019-12-09 21:41:24 【问题描述】:

我正在尝试在 Vapor 3 和 Fluent 中进行嵌套查询。关键是我需要从每个团队拥有特定 eventID 的团队中获取所有用户。团队是 Event 的子代。用户是 Teams 的子级。在此先感谢您的帮助。 每个活动只有 15 个团队,但每个团队有 12 个用户

这里是事件模型:

final class Event: Codable     
    var id: Int?
    var name: String


extension Event 
    var teams: Children<Event, Team> 
        return children(\.eventID)
    

这是团队模型

final class Team: Codable     
    var id: Int?
    var name: String
    var icon: String
    var eventID: Event.ID


extension Team 
    var user: Parent<Team, Event> 
        return parent(\.eventID)
    


extension Team 
    var users: Children<Team, User> 
        return children(\.teamID)
    

这是用户模型。

final class User: Codable 
    var id: UUID?
    var name: String
    var email: String
    var eventID: Event.ID
    var teamID: Team.ID


extension User 
    var user: Parent<User, Team> 
        return parent(\.teamID)
    

我需要发送一个事件 ID,我希望它返回所有团队中的所有用户

func getUsersForEvent(_ req: Request) throws -> Future<[User]>         
    return try req.parameters.next(Event.self).flatMap(to: [User].self)  event in
        return try event.teams.query(on: req).all().flatMap(to: [User].self)  team in
            return try team.users.query(on: req).all()
        
    

【问题讨论】:

【参考方案1】:

您可以使用原始 SQL 查询或使用 SwifQL 库轻松查询

这是一个使用 SwifQL 的示例

struct TeamWithUsers: Content 
    let id: UUID
    let name, icon: String
    let users: [User]


func getCategoriesWithProducts(_ req: Request) throws -> Future<[TeamWithUsers]> 
    return try req.parameters.next(Event.self).flatMap  event in
        let usersSubquery = SwifQL
            .select(Fn.coalesce(Fn.array_agg(Fn.to_jsonb(User.table)), PgArray() => .jsonbArray))
            .from(User.table)
            .where(\User.teamID == \Team.id)
        let query = try SwifQL
            .select(\Team.id, \Team.name, \Team.icon, |usersSubquery | => "users")
            .from(Team.table)
            .where(\Team.eventID == event.requireID())
        // here you could print the raw query for debugging
        // print(query.prepare(.psql).plain)
        return query.execute(on: req, as: .psql).all(decoding: TeamWithUsers.self)
    

【讨论】:

【参考方案2】:

在 Ray Wenderlich 的书的帮助下,这是我的想法。在我的任务中,我不需要返回所有用户,一次只需要查看 1 个事件的团队,因此我将 eventID 作为参数传递。

关于如何按 teamScore 对结果进行排序的任何指导?

func getTeamsWithUsersForEvent(_ req: Request) throws -> Future<[TeamWithUsers]> 
    let currentID =  try req.parameters.next(Int.self)
    print("currentID \(currentID)")
    return Team.query(on: req).filter(\Team.eventID == currentID).all().flatMap(to: [TeamWithUsers].self)  team in
        try team.map  team in
            try team.users.query(on: req).all().map  users in
                TeamWithUsers(
                    id: team.id,
                    name: team.name,
                    icon: team.icon,
                    eventID: team.eventID,
                    //rawScore: team.rawScore,
                    //users: users,
                    count: users.count,
                    teamScore: team.rawScore / users.count
                )
            
        .flatten(on: req)
    


struct TeamWithUsers: Content 
    let id: Int?
    let name: String
    let icon: String
    let eventID: Event.ID
    //let rawScore: Int
    //let users: [User]
    let count: Int
    let teamScore: Int

【讨论】:

以上是关于Vapor 3 和 Fluent - 嵌套查询的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Vapor/Fluent 中正确查询 Postgres JSONB 字段

在 Vapor 命令中使用 Fluent

Swift Vapor 服务器:如何在获取请求中返回嵌套字典?

Vapor 2,Fluent 模型子类

Vapor fluent 不会在违反外键约束时抛出

如何从 Vapor 3 中的 JSON 响应中保存父子关系