Fluent 查询 封面
Vapor 大型教程

Fluent 查询

Fluent 查询从 all() 和 first() 开始,还包括过滤、或条件、排序和取首条记录。示例都围绕 Acronym 模型,方便直接对照使用。

请求示例:http://localhost:8080/api/acronyms/search?term={searchItem}

Search:单字段过滤

router.get("api", "acronyms", "search") { (req) -> Future<[Acronym]> in
    guard let searchItem = req.query[String.self, at: "term"] else {
        throw Abort(.badRequest)
    }
    return Acronym.query(on: req)
    .filter(\.short == searchItem)
    .all()
}

Search:多字段或查询

router.get("api", "acronyms", "search") { (req) -> Future<[Acronym]> in
    guard let searchItem = req.query[String.self, at: "term"] else {
        throw Abort(.badRequest)
    }
    return Acronym.query(on: req).group(.or) { (or) in
        or.filter(\.short == searchItem)
        or.filter(\.long == searchItem)
    }
    .all()
}

First

router.get("api","acronyms","first") { (req) -> Future<Acronym> in
    return Acronym.query(on: req).first().map(to: Acronym.self) { (acronym)  in
        guard let acronym = acronym else {
            throw Abort(.notFound)
        }
        return acronym
    }
}

或者更简单一点就是:

func firstHandler(_ req: Request) throws -> Future<Acronym> {
    return Acronym.query(on: req).first().unwrap(or: Abort(.notFound))
}

Sort

router.get("api","acronyms","sorted") { (req) -> Future<[Acronym]> in
    return Acronym.query(on: req).sort(\.short, .ascending).all()
}

查询性能与分页

示例适合学习 API,但生产列表接口不应无条件调用 all()。数据量增长后应使用分页参数,并为常用筛选字段建立索引;同时限制客户端可请求的最大页大小,避免一次查询拖慢整个事件循环。

// 伪代码:先限制页大小,再执行排序和分页
let pageSize = min(req.query[Int.self, at: "limit"] ?? 20, 100)
let page = max(req.query[Int.self, at: "page"] ?? 1, 1)

查询条件来自用户输入时不要拼接 SQL 字符串,始终使用 Fluent 的参数化过滤。为慢查询记录耗时和条件摘要,不记录完整的敏感查询参数。


本系列其他文章