关联查询
最后更新于
关联查询数据是API开发中的常见用例。有两种形式的关联查询:有外键关联和跨源关联。
在查询某个对象的同时,获取其关联对象,对应sql left join。使用关联查询,需要在数据库表间建立外键。
基于超图面板对 gql 的可视化封装,能充分发挥其嵌套查询的优势。甚至不需要掌握 SQL,就能构建多级的嵌套查询。
如图所示有4张主表,其中 User
和 Profile
是1:1关联,User
和 Post
是 1对多关联,Post
和Category
是多对多关联。
其 Prisma Model 如下:
如何用prisma model建立关联关系,可参考Prisma文档
我们构建了如图所示多级嵌套查询 OPERATION,以 User
表为主体,查询到的 Profile
是对象,查询到的 Post
是数组,Post
中的 Category
也是数组。
在架构图中,我们提到过飞布引擎做了很多性能优化,其中之一是N+1查询优化。
我们以示例讲解下,飞布如何实现查询优化。
还以上述表为例,User
和 Post
为1对多关联,这时候我们构建了一个新的 Operation
,查询 Post
的 User
,即查询文章的同时拿到作者信息。可以看到如下响应,其中 User
为对象。
这里有个问题,3条 Post
的作者是同一个,是否意味着:飞布会查询3次用户?类似上图,先查询所有文章,然后遍历文章,挨个查询作者,最后再合并。
实际上,在底层我们做了N+1查询优化,用 where in 的方式避免了无用的查询。将上述 sql 改成了:先查询所有文章,然后用文章的作者id注入where in语句中。
这样能提升查询性能,避免不必要的数据库请求。
默认情况下,OPRATION 都是并行执行,但很多场景需要先查询数据,然后将返回值作为条件,执行下一个查询/变更。
跨源关联有两种常见用例:
同一数据库表间未建立外键(虚拟外建更适合,详情见 prisma 数据源)
跨数据源关联查询/变更
举个物联网的例子:设备列表页,不仅要展示设备列表,还要展示设备在线状态。
传统模式下,我们需要先从数据库获取设备列表,然后遍历数据,逐个调用物联网平台接口获取设备在线状态,最后拼接数据返回给客户端。用编码的方式,大概需要几百行代码。
而利用飞布的跨源关联功能,只需要几行 GraphQL OPERATION 就能实现上述需求。
跨源关联本质上是一种流程编排,将通常情况下并行的请求,改造成串行。
使用跨源关联,至少需要配置两个数据源(或同一数据源两个不同函数)。
跨源查询,将上一个返回值作为参数传给下一个查询。
例如,db为数据库,iot为物联网 REST API。以下示例展示了:先用 db_findManyDevice
查询设备列表,然后用 iot_deviceState
查询设备在线状态。
上述示例,主要分为三个环节:
声明:@internal
指令从公开API中移除 $device_id
变量。这意味,用户不能手工设置它。我们称它为关联键(join key)。
赋值:使用 @export
指令,我们可以将字段 id
的值导出给关联键($device_id
)
使用:一旦我们进入 _join
字段,我们可以使用 $device_id
变量去关联物联网 API
其中涉及到两个知识点:
指令: @internal
用于定义变量;@export
用于赋值变量。
_join
字段:_join
字段是一个特殊的字段,是 QUERY 类型。
_join
这种定义方式,实现了循环嵌套,详情可查看文件:exported/generated/fireboom.app.schema.graphql
跨源更新,将上一个返回值作为参数传给下一个变更。
例如,blog为数据库1,todo为数据库2。以下示例展示了:先用 blog_findUniqueUser
查询用户(id=1),然后用 todo_updateManyTodo
更新该用户的所有待做事项为 未完成 (completed=false)。
跨源更新与跨源查询的指令基本一致,除了 _join
变成了 _join_mutation
。_join_mutation
是 MUTATION 类型。