飞布产品手册
官网B站Github
V2.0
V2.0
  • 序言
  • 更新日志
    • 更新日志V2.0
    • V2.0更新说明
    • 更新日志V1.0
  • 产品简介
    • 什么是飞布?
    • 飞布的价值
    • 飞布的优势
    • 应用场景
    • 数据安全
    • 产品案例
  • 快速入门
    • 初识飞布
    • 快速上手
      • 图文版
    • 词汇概览
    • 工作原理
  • 基础-可视化开发
    • 概览
      • CLI
      • 控制台
        • 主功能区
    • 数据源
      • 数据库
        • 数据库连接
          • 高级设置
        • 数据建模
        • 数据预览
      • Prisma 数据源
      • REST 数据源
      • GraphQL 数据源
      • 消息队列
    • API构建
      • 可视化构建
        • API规范
      • 批量新建
      • HTTP请求流程指令
      • 使用API
      • 实时查询
      • 实时推送
      • 关联查询
      • 数据缓存
      • 常见用例
    • 身份验证
      • 授权码模式
        • 身份验证(废弃)
      • 隐式模式
      • 数据权限控制
    • 身份授权
      • RBAC
        • 授权与访问控制(废弃)
      • 接口权限控制
      • 开放API
    • 文件存储
      • S3配置及使用
      • 文件管理面板
      • 高级配置:profile
  • 进阶-钩子机制
    • 钩子概览
    • 启动钩子
      • Node钩子
      • Golang钩子
      • Java钩子
      • Python钩子
    • OPERATION钩子
    • 身份验证钩子
    • graphql钩子
    • 函数钩子
      • function
      • proxy
    • 文件上传钩子
    • 内部调用
  • 使用-部署上线
    • 部署运维
      • 手动部署
        • 流水线部署(废弃)
      • Docker部署
      • 飞布云
      • sealos部署
    • 接口安全
      • CSRF token 保护
      • 跨域访问
    • 客户端SDK
      • Js SDK
      • 微信小程序SDK
      • Flutter SDK
      • uniapp SDK
    • 性能测试
  • 迁移到V2
  • 环境准备
    • 文件存储 S3
    • 身份认证 OIDC
    • NodeJs环境
  • 实战案例
    • Amis Admin
      • 管理后台-refine(废弃)
    • 实时TODO LIST
    • 语音版ChatGPT
    • AI魔法师实战
    • 阿里低代码引擎
    • appsmith集成
  • Roadmap
  • 常见问题
  • 核心概念
    • GraphQL
    • 超图
    • 请求时序图
    • 服务端Operation
  • 二次开发
    • 钩子规范
      • 钩子规范bak
    • 模板规范
    • 自定义模板
    • 其它参考
由 GitBook 提供支持
在本页
  • 有外键关联(嵌套关联)
  • N+1 查询
  • 跨源关联
  • 跨源查询
  • 跨源更新

这有帮助吗?

在GitHub上编辑
  1. 基础-可视化开发
  2. API构建

关联查询

上一页实时推送下一页数据缓存

最后更新于1年前

这有帮助吗?

关联查询数据是API开发中的常见用例。有两种形式的关联查询:有外键关联和跨源关联。

有外键关联(嵌套关联)

在查询某个对象的同时,获取其关联对象,对应sql left join。使用关联查询,需要在数据库表间建立外键。

基于超图面板对 gql 的可视化封装,能充分发挥其嵌套查询的优势。甚至不需要掌握 SQL,就能构建多级的嵌套查询。

如图所示有4张主表,其中 User 和 Profile 是1:1关联,User 和 Post 是 1对多关联,Post 和Category 是多对多关联。

其 Prisma Model 如下:

prisma model
model Category {
  id   Int    @id @default(autoincrement())
  name String
  Post Post[]
}

model Post {
  id        Int        @id @default(autoincrement())
  createdAt DateTime   @default(now())
  title     String
  published Boolean    @default(false)
  authorId  Int
  User      User       @relation(fields: [authorId], references: [id])
  Category  Category[]

  @@index([authorId], map: "Post_authorId_fkey")
}

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  userId Int    @unique
  User   User   @relation(fields: [userId], references: [id])
}
model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  role    String   @default("admin")
  Post    Post[]
  Profile Profile?
}

我们构建了如图所示多级嵌套查询 OPERATION,以 User 表为主体,查询到的 Profile 是对象,查询到的 Post 是数组,Post 中的 Category 也是数组。

query MyQuery {
  mysql_findFirstUser {
    id
    name
    email
    # 1:n关联:post为对象数组
    Post(where: {title: {contains: "test"}}) {
      id
      title
      # n:n关联:category为对象数组
      Category {
        id
        name
      }
    }
    # 1:1关联:profile为对象
    Profile {
      id
      userId
    }
  }
} 

N+1 查询

在架构图中,我们提到过飞布引擎做了很多性能优化,其中之一是N+1查询优化。

我们以示例讲解下,飞布如何实现查询优化。

还以上述表为例,User 和 Post 为1对多关联,这时候我们构建了一个新的 Operation ,查询 Post 的 User,即查询文章的同时拿到作者信息。可以看到如下响应,其中 User 为对象。

这里有个问题,3条 Post 的作者是同一个,是否意味着:飞布会查询3次用户?类似上图,先查询所有文章,然后遍历文章,挨个查询作者,最后再合并。

实际上,在底层我们做了N+1查询优化,用 where in 的方式避免了无用的查询。将上述 sql 改成了:先查询所有文章,然后用文章的作者id注入where in语句中。

这样能提升查询性能,避免不必要的数据库请求。

跨源关联

默认情况下,OPRATION 都是并行执行,但很多场景需要先查询数据,然后将返回值作为条件,执行下一个查询/变更。

跨源关联有两种常见用例:

  • 跨数据源关联查询/变更

举个物联网的例子:设备列表页,不仅要展示设备列表,还要展示设备在线状态。

传统模式下,我们需要先从数据库获取设备列表,然后遍历数据,逐个调用物联网平台接口获取设备在线状态,最后拼接数据返回给客户端。用编码的方式,大概需要几百行代码。

而利用飞布的跨源关联功能,只需要几行 GraphQL OPERATION 就能实现上述需求。

跨源关联本质上是一种流程编排,将通常情况下并行的请求,改造成串行。

使用跨源关联,至少需要配置两个数据源(或同一数据源两个不同函数)。

跨源查询

跨源查询,将上一个返回值作为参数传给下一个查询。

例如,db为数据库,iot为物联网 REST API。以下示例展示了:先用 db_findManyDevice 查询设备列表,然后用 iot_deviceState 查询设备在线状态。

query MyQuery($device_id:Int! @internal) {  # 声明:定义变量 $device_id
  db_findManyDevice {
    id @export(as:"device_id")# 赋值: $device_id = id
    name
  # _join 字段返回类型Query!
  # 它存在于每个对象类型上,所以你可以在Query文档的任何地方看到它
    _join{
      iot_deviceState(device_id: $device_id) { # 使用:将 $device_id 设置给 device_id 变量 
        status
      }
    }
  } 
}

上述示例,主要分为三个环节:

  • 声明:@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)。

query MyQuery($authorId: Int! @internal) {
  blog_findUniqueUser(where: {id: 1}) {
    email
    id @export(as: "authorId")
    _join_mutation {
      todo_updateManyTodo(where:{authorId:{equals:$authorId}},data:{completed:{set:false}}) {
        count
      }
    }
  }
}

跨源更新与跨源查询的指令基本一致,除了 _join 变成了 _join_mutation 。_join_mutation是 MUTATION 类型。

如何用prisma model建立关联关系,可参考

同一数据库表间未建立外键(虚拟外建更适合,详情见 )

Prisma文档
prisma 数据源
11功能介绍-飞布如何实现跨源关联?_哔哩哔哩_bilibili
11功能介绍-飞布如何实现跨源关联?
跨源关联时序图
Logo