Vapor 2.0 - 查询(Query)

前往 Vapor 2.0 - 文档目录

Fluent的查询构建器提供了一个创建复杂数据库查询的简单界面。在Query类本身(不包含原始查询)是通过Fluent的与数据库通信的唯一方法。

构造(Make)

您可以从任何模型类创建一个新的查询构建器。

let query = try Post.makeQuery()

您还可以从实例创建查询。如果您需要使用特殊的数据库连接(如事务处理(transactions))来保存或更新模型,这一点尤其有用。

guard let post = try Post.find(42) else { ... }
post.content = "Updated"
let query = try post.makeQuery(conn).save()

获取(Fetch)

您有多个选项用于获取查询的结果。

全部(All)

最简单的选项.all()返回与查询相关的所有行。

let users = try User.makeQuery().filter(...).all()

首先(First)

你也可以用.first()只获取第一行。

let user = try User.makeQuery().filter(...).first()

Fluent会自动将结果限制为1,以提高查询的性能。

数据块(Chunk)

如果要从数据库中获取大量的模型,则使用.chunk()可以帮助通过一次获取数据块来减少查询所需的内存量。

User.makeQuery().filter(...).chunk(32) { users in
    print(users)
}

过滤器(Filter)

过滤器允许您选择想要修改或获取的数据子集。有三种不同类型的过滤器。

比较(Compare)

比较过滤器在数据库中的模型和提供的值之间进行比较。

try query.filter("age", .greaterThanOrEquals, 21)

你也可以使用运算符。

try query.filter("age" >= 21)
案例Case 运算符Operator 类型Type
.equals == Equals
.greaterThan > Greater Than
.lessThan < Less Than
.greaterThanOrEquals >= Greater Than Or Equals
.lessThanOrEquals <= Less Than Or Equals
.notEquals != Not Equals
.hasSuffix Has Suffix
.hasPrefix Has Prefix
.contains Contains
.custom(String) Custom

提示
您可以省略比较类型.equals,例如,query.filter("age", 23)

子集(Subset)

您还可以根据一组数据中的字段进行筛选。

try query.filter("favoriteColor", in: ["pink", "blue"])

或者相反。

try query.filter("favoriteColor", notIn: ["brown", "black"])

组(Group)

默认情况下,所有的查询过滤器都是与(AND)逻辑连接的。您可以在您的查询中创建一组过滤器,这些过滤器是与(AND)或或(OR)逻辑一起连接的。

try query.or { orGroup in
    try orGroup.filter("age", .greaterThan, 75)
    try orGroup.filter("age", .lessThan, 18)
}

这将导致SQL类似于以下内容:

SELECT * FROM `users` WHERE (`age` > 75 OR `age` < 18);

.and()也是可用的,以防您需要用嵌套了一个或(OR)的与(AND)来切换回连接过滤器。

复杂示例(Complex Example)
let users = try User
    .makeQuery()
    .filter("planetOfOrigin", .greaterThan, "Earth")
    .or { orGroup in
        orGroup.and { andGroup in
            andGroup.filter("name", "Rick")
            andGroup.filter("favoriteFood", "Beer")
        }
        orGroup.and { andGroup in
            andGroup.filter("name", "Morty")
            andGroup.filter("favoriteFood", "Eyeholes")
        }
    }
    .all()

这将导致SQL类似于以下内容:

SELECT * FROM `users`
    WHERE `planetOfOrigin` = 'Earth' AND (
           (`name` = 'Rick' AND `favoriteFood` = 'Beer')
        OR (`name` = 'Morty' AND `favoriteFood` = 'Eyeholes')
    )

注意
请记住,组的AND / OR逻辑仅适用于组内添加的过滤器。过滤器组外的所有过滤器将由AND连接。

原始(Raw)

原始过滤器可用于通过不应参数化的值进行过滤。

try query.filter(raw: "date >= CURRENT_TIMESTAMP")

不同(Distinct)

要仅从数据库中选择不同的模型,请添加.distinct()到您的查询中。

try query.distinct()

限制/偏移(Limit / Offset)

要限制或偏移查询,请使用该.limit()方法。

try query.limit(20, offset: 5)

排序(Sort)

要对查询的结果进行排序,请使用该.sort()方法。

try query.sort("age", .descending)

您可以通过链接您的.sort()调用一次对多个列进行排序。

try query.sort("age", .descending).sort("shoe_size")

加入(Join)

您可以将两个模型表连接在一起,如果要通过另一个模型的属性过滤一个模型,这将非常有用。例如,假设你有一个属于Departments的Employees表。你想知道哪个部门包含已经完成了十年服务的员工。

首先,使用.join()部门查询中的方法将其与Employee表一起加入。接下来你链接.filter()到查询。请记住,您需要将“已连接”模型显式传递给过滤器,否则Fluent将尝试在“基本”模型上过滤。

let departments = try Department.makeQuery()
  .join(Employee.self)
  .filter(Employee.self, "years_of_service" >= 10)

Fluent将为您提供关系领域,但您也可以使用baseKeyjoinedKey方法参数指定它们,baseKey“base”模型(Department)上的标识符字段在哪里,并且joinedKey是“加入”模型的外键字段(员工)涉及“基地”模式。

提示
Fluent支持内部和外部连接; 使用调用.join(kind: .outer, MyModel.self)

原始(Raw)

如果您需要执行查询构建器不支持的查询,则可以使用原始查询。

try drop.database?.raw("SELECT @@version")

您也可以使用给定模型的数据库。

User.database?.raw("SELECT * FROM `users`")

除了为查询数据库提供了一个更具表达性的接口外,查询构建器还采取了一些措施,通过自动清除输入来增加安全性。因此,可以尝试使用查询类来执行原始查询。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容