本文属使用Prisma构建GraphQL服务系列。
Prisma API提供两种查询:
- 对象查询:获取某个对象类型的单个或多个节点
- 连接查询:暴露高级功能,如聚合(aggregation)和 Relay compliant connections实现强大的分页模型
在使用Prisma API时,以下功能也是值得留意:
- 分层查询:跨关系提取数据
- 查询参数:允许过滤,排序,分页等
通常,Prisma API服务是基于其数据模型生成的。要查看Prisma API中的操作,可以使用GraphQL Playground。
在下文中,我们将看看基于如下数据模型的Prisma服务示例查询:
type Post {
id: ID! @unique
title: String!
published: Boolean!
author: User!
}
type User {
id: ID! @unique
age: Int
email: String! @unique
name: String!
accessRole: AccessRole
posts: [Post!]!
}
enum AccessRole {
USER
ADMIN
}
对象查询
我们可以使用对象查询来获取单个节点或某个对象类型的节点列表。
在这里,我们使用posts
查询来获取Post
节点的列表。在响应中,只包含每个Post
节点的id
和title
:
query {
posts {
id
title
}
}
我们还可以使用post
查询来查询特定的Post
节点。请注意,我们使用where
参数来选择节点:
query {
post(where: {
id: "cixnen24p33lo0143bexvr52n"
}) {
id
title
published
}
}
由于User
是我们数据模型中的另一种类型,因此users
是另一种可用查询。再次,我们可以使用where
参数为返回的User
指定条件。在这个例子中,我们筛选所有age
大于18岁的User
节点:
query {
users(where: {
age_gt: 18
}) {
id
name
}
}
这也适用于所有关系,在这里我们提取那些age
大于18岁的author
的Post
节点:
query {
posts(where: {
author: {
age_gt: 18
}
}) {
id
title
author {
name
age
}
}
}
连接查询(Connection queries)
对象查询直接返回节点列表。在特殊情况下或使用高级功能时,使用连接查询是首选选项。它们是中继连接(Relay connections)的延伸(并且完全符合)。中继连接的核心思想是提供关于数据图中边缘的元信息。例如,每条边不仅可以访问关于相应对象(节点)的信息,还可以与允许实现强大分页的游标相关联。
在这里,我们使用postsConnection
查询获取所有Post
节点。注意我们也要求每个边的cursor
:
# Fetch all posts
query {
postsConnection {
edges {
cursor
node {
id
title
}
}
}
}
连接查询还通过aggregate
显示聚合功能:
# Count all posts with a title containing 'GraphQL'
query {
postsConnection(where: {
title_contains: "GraphQL"
}) {
aggregate {
count
}
}
}
跨关系查询数据
数据模型中的每个可用关系都会为它所连接的两个模型的查询添加一个新字段。
在这里,我们正在使用posts
字段获取特定的User
以及所有相关的Post
节点:
query {
user(where: {
id: "cixnekqnu2ify0134ekw4pox8"
}) {
id
name
posts {
id
published
}
}
}
嵌套的user.posts
的行为与顶级posts
查询完全相同,因为它允许您指定您感兴趣的Post
类型的哪些字段。
查询参数
在整个Prisma API中,您会发现可以提供的查询参数以进一步控制查询响应。查询参数有:
- 使用
orderBy
按节点任何字段值排序 - 通过使用
where
的标量或关系过滤器在查询中选择节点 - 查询字符串中使用
first
、before
、last
、after
和skip
对节点分页
排序
查询某个类型的所有节点时,可以为每个类型的标量字段提供orderBy
参数:orderBy: <field>_ASC
或 orderBy: <field>_DESC
。
按照title
升序排序:
query {
posts(orderBy: title_ASC) {
id
title
published
}
}
按published
降序排序:
query {
posts(orderBy: published_DESC) {
id
title
published
}
}
注意:您所排序的字段不必在实际查询中选择。如果您没有指定顺序,则响应会自动按
id
字段升序排列。
当前版本不支持按多个字段或关联字段排序
过滤
查询某个类型的所有节点时,可以根据需要为where
参数提供不同的参数以约束返回的数据。可用选项取决于所讨论类型上定义的标量和关系字段。
单个过滤
如果您只向where参数提供一个参数,则查询响应将只包含遵守此约束的节点。多个过滤器可以使用AND
、OR
进行组合,详见下文。
1. 按值过滤
过滤查询响应的最简单方法是提供一个字段值进行过滤。
查询尚未发布(published
为false
)的所有Post
节点:
query {
posts(where: {
published: false
}) {
id
title
published
}
}
2. 高级过滤
根据您要过滤的字段的类型,您可以使用不同的高级标准来筛选查询响应。
查询title
在给定字符串列表中的所有Post
节点:
query {
posts(where: {
title_in: ["My biggest Adventure", "My latest Hobbies"]
}) {
id
title
published
}
}
注意:您必须提供一个列表作为
<field> _in
参数:title_in: ["My biggest Adventure", "My latest Hobbies"]
。
关系过滤
对于一对一关系,可以通过将相关参数嵌套在相关节点中来定义条件。
查询其作者角色为USER
的所有Post
节点:
query {
posts(where: {
author: {
accessRole: USER
}
}) {
title
}
}
对于多对多关系,可以使用三个附加参数:every
,some
和none
,来定义条件应该匹配every
,some
和none
相关节点。
查询至少有一个Post
已发布(published
为true
)的所有用户节点:
query {
users(where: {
posts_some: {
published: true
}
}) {
id
posts {
published
}
}
}
关系过滤器也可用于一对一或多对多关系的嵌套参数。
查询不喜欢ADMIN
角色作者的帖子的所有用户节点:
query {
users(where: {
likedPosts_none: {
author: {
accessRole: ADMIN
}
}
}) {
name
}
}
注意:
likePosts
不是上述数据模型的一部分,但可以通过将相应的字段添加到User
类型中:likedPosts: [Post!]! @relation(name: "LikedPosts")
。请注意,为避免歧义,我们还为关系提供了一个名称。
组合过滤
您可以使用过滤器组合器OR
,AND
,NOT
创建过滤器条件的任意逻辑组合。
使用OR
,AND
和NOT
查询发布的所有Post
节点,其title
包含在给定的字符串列表中:
query {
posts(where: {
AND: [{
title_in: ["My biggest Adventure", "My latest Hobbies"]
}, {
published: true
}]
}) {
id
title
published
}
}
注意:
OR
,AND
和NOT
并接受一个列表作为输入,其中每个列表项都是一个对象,因此需要用{}
进行包装,例如:AND: [{title_in: ["My biggest Adventure", "My latest Hobbies"]}, {published: true}]
带有AND
,OR
和NOT
的过滤的任意组合
您可以组合甚至嵌套过滤器组合器AND
,OR
和NOT
来创建过滤条件的任意逻辑组合。
查询所有已发布并且其title
在给定字符串列表中的Post
节点,或者查询我们提供的特定id
:
query($published: Boolean) {
posts(where: {
OR: [{
AND: [{
title_in: ["My biggest Adventure", "My latest Hobbies"]
}, {
published: $published
}]
}, {
id: "cixnen24p33lo0143bexvr52n"
}]
}) {
id
title
published
}
}
请注意,我们是如何将
AND
组合器嵌套在OR
组合器中的,与id
值过滤器处于同一级别。
除了过滤器组合器AND
,OR
和NOT
之外,用于查询类型的所有节点的可用过滤器参数取决于类型的字段及其类型。
目前,既没有标量列表过滤器( scalar list filters)也没有JSON过滤器(JSON filters)可用。在GITHUB的各个特征请求中加入讨论。
分页
查询特定对象类型的所有节点时,可以提供允许您对查询响应进行分页的参数。
分页允许您同时请求一定数量的节点。您可以通过节点向前或向后寻找并提供可选的起始节点:
- 向前,使用
first
;使用指定起始节点的after
- 向后,使用
last
,使用指定起始节点的before
通过提供skip
参数,您还可以跳过任意数量的节点,无论您正在寻找哪个方向。
考虑一个博客,其中只有3个Post节点显示在首页。要查询第一页:
query {
posts(first: 3) {
id
title
}
}
在第一个Post节点之后查询前两个Post节点:
query {
posts(
first: 2
after: "cixnen24p33lo0143bexvr52n"
) {
id
title
}
}
我们可以通过结合first
和skip
来达到相同的结果:
query {
posts(
first: 2
skip: 1
) {
id
title
}
}
查询最后2个Post
:
query {
posts(last: 2) {
id
title
}
}
注意:您不能
first
与before
或last
于after
混合,您还可以查询更多的节点,而不会出现错误消息。
请注意,共享演示群集上的每个分页字段最多可以返回1000个节点。使用群集配置(the cluster configuration)的其他群集可以提高此限制。