代码块
代码块节点允许用户在行为流中编写 JavaScript 代码,处理入参和出参,执行复杂逻辑。
使用教程
添加代码块
在行为流中添加代码块节点。
配置代码块
添加后可点击代码块节点修改名称,并在右侧编辑区直接编写 JS 代码。也可点击编辑器右上角“展开”按钮,使用大窗口编辑。
配置及获取入参
如需在代码块中处理行为流入参或上级节点数据,需先在行为流中配置入参,再在代码块节点中配置入参,最后在代码中通过 context.getArg('参数名')
获取。
const thing1 = context.getArg('thing1')
const thing4 = context.getArg('thing4')
const date2 = context.getArg('date2')
const accountId = context.getArg('accountId')
配置及返回出参
如需将代码块处理结果传递给下游节点,需在代码块中用 context.setReturn('出参名称', 参数内容)
返回,并在节点配置中声明出参。
- 代码块中设置返回值
const phone_number = context.getArg('phone_number')
const result = `${phone_number.substring(0, 3)}****${phone_number.substring(7, 11)}`
context.setReturn('result_phone', result)
- 代码块节点配置出参
出参的名称要与上一步中的 context.setReturn()
函数中填写的名称一致

- 在「行为流」中配置出参,这里的作用是将上级节点中需要给前端使用的数据返回到前端,进行了这一步之后,在前端页面调用这个行为流时,才会有【结果数据】供页面赋值/使用

高阶内容
本节详细介绍如何在 Zion 平台的代码块中使用 GraphQL 进行数据库操作,包括前提条件、操作步骤、代码示例,以及在 Zion 中配置和调用第三方 API 的方法。 前提条件:
- 精通 Zion 的使用
- 了解 SQL
- 下载并会使用 Altair GraphQL Client , gql 参考文档
⚠️⚠️⚠️ 注意:保护好自己的 Authorization,一旦泄露别人可以随便通过 gql 操作你的数据,所以为了防止别人能够通过 gql 随意操作你的数据库 ,你需要参考 【权限管理配置说明】定义好你的数据库访问权限。
教学视频:【 gql 专讲 1 】 ,【 gql 专讲 2 】
应用场景
期望直接在代码块中读取或者修改数据库中的数据,以便于拿到数据后进行代码逻辑的处理
GraphQL 基本简介与作用
GraphQL 是 Facebook 于 2012 年在内部开发的数据查询语言
- Zion 中数据的读取和操作基于 GraphQL (以下简称 gql ) 规范
- 将 GraphQL 植入 ActionFlow 中,即可在 Zion 的行为流中定义各种代码块,实现复杂的功能需求,例如各类批量操作
- Altair: Altair GraphQL Client 是调试 gql 的工具,以下简称 Altair,下载打开后的界面如下所示

在代码块中运行 gql
代码示例:
// 1. 定义 gql 语句
const gql = `query findBlogById ($blogId: bigint!){
blog(where: {id:{_eq: $blogId}}) {
id
title
content
}
}`
// 2. 运行 gql
const result = context.runGql(
'findBlogById',
gql,
{ blogId: 1 },
{ role: 'admin' }
)
// 3. 从结果中提取数据
const status = result.blog[0].status;
代码说明
- 定义 gql 语句。字符串类型,里面包含以下内容:
-
操作类型: 在语句的开头指明操作类型,例如 query (查询数据)、mutation (修改数据) 或 subscription (订阅数据变更)。
-
操作名称: 给操作指定一个名称,例如
findBlogById
。这个名称在调试和日志记录中非常有用,并且也是 context.runGql 函数的第一个参数。 -
变量定义: 在操作名称后的括号 () 内,你可以定义查询所需要的变量。每个变量都以 $ 开头,后跟变量名和类型,例如
($blogId: bigint!)
。 -
查询主体: 在花括号 内,你将指定需要从哪个表或视图查询数据(例如
blog
),并列出你希望返回的具体字段(如id
,title
,content
等)。
- 运行 gql
通过调用 context.runGql( operationName , gql , variables , permission )
函数来执行 gql 语句。该函数接受四个参数:
operationName: 操作名称。必须与你在 gql 语句中定义的操作名称(即 query 或 mutation 关键字后面的名称)完全一致。在此示例中为 findBlogById
。
gql: 即上一步中定义的 gql 语句。
variables: 变量对象。这是一个对象,用于传递在 GraphQL 语句中定义的变量。对象的键名需要与 gql 语句中的变量名(去掉 $ 符号)相匹配,值则是你要传入的具体数据。例如 { blogId: 1 }
会将值 1 传递给 GraphQL 中的 $blogId
变量。如果 gql 语句没有定义变量,可以传入一个空对象。
permission: 权限角色。一个用于指定本次操作所用权限角色的对象。这在需要以特定用户角色(如管理员)身份执行操作时非常关键。在示例中,{ role: 'admin' }
表示以“admin”管理员的角色的权限来运行此查询。
- 从结果中提取数据
context.runGql 函数执行成功后,会返回一个包含了查询结果的对象。这个对象的结构与你在 gql 查询主体中定义的结构对应。
例如,在之前的 gql 查询中,我们请求的结构是:
query findBlogById ($blogId: bigint!){
blog(where: {id:{_eq: $blogId}}) {
id
title
content
}
}
因此,返回的 result 对象将会是这样的结构:
{
"blog": [
{
"id": 1,
"title": "title",
"content": "content"
}
]
}
根据对象的数据结构,可以用 result.blog[0].status
来提取想要的内容。
不同的操作类型,返回的数据结构有差别。具体可查看下方的【Altair 调试 gql 配置内容】中的请求说明。
Altair 调试 gql 配置内容
- 设置 Headers 和方法
- 添加服务器 URL
- 点击 Docs 查看完整的 GraphQL 架构文档
- 配置 Varaibles

配置请求 URL 以及 Headers
接下来用一个例子说明如何使用 Altair 调试 Zion 的接口。
- 进入 Zion 创建一个新的项目,创建一张名为 reference 的数据表,在数据表中添加 content(文本)的字段,同步后端
- 按 F12 打开浏览器控制台,点击“网络”并清空。接着,在 Zion 编辑器中打开“数据库”选项卡,并进入 reference 表。此时,您就能在控制台中看到获取 reference 表数据的请求了。

- 复制 Headers 下 General 中的 Request URL 中的内 URL 粘贴至 Altair 的请求中,请求方式为POST;
- 复制 Headers 下 General 中的 Request Headers 中的 Authorization 以及其值 粘贴到 Altair 请求头中

如何查看文档
配置一个 query 请求,请求 reference 表中的数据,点击 Altair 右侧的 Docs,输入reference,可以看到关于这张数据表的请求都在这里,选择第一个,可以看到在这个请求下的左右参数、类型、字段,你可以点击任何一个内容来进一步了解请求配置

- ARGUMENTS 请求参数: 在请求数据时,一般需要配置 where(条件)、order_by(排序字段)、distinct_on(字段内容去重)、offset(从第几项开始,index)、limit(限额)
- 请求参数类型判断:没有任何符号的,那么就是一个对象,有一个[]的,是一个数组,具体的类型(比如 int )
- 请求参数的选择:点击某个请求参数,可以查看该参数下能够配置哪些内容,点击内容,能够查看该内容能够配置哪些运算符(判断方法)
- 基本的比较运算符(判断方法):
- 等于(_eq)、为空(_is_null:true)、非空:(_is_null:false)
- 大于等于(_gte)、小于等于(_lte)
- 与条件_and:[条件1,条件2]、或条件_or:[条件1,条件2],、非条件_not:条件
- 大于(_gt)、小于(_lt)
- 包含(_in)、不包含(_nin)
- 相似(_like)、不相似(_nlike)、不区分大小写的相似(_ilike)
- 自增(_inc)
- 排序:降序(desc)、升序(asc)
- TYPE 类型:返回值的类型
- FIELDS 字段: 返回值中的具体字段
Query - 查询请求
搜索请求
在文档中搜索某张表名,找到这张表的 query 请求,点击该请求进入到请求详细信息

添加请求
鼠标悬浮到最上方表名时,右侧可以点击 ADD QUERY,会自动将请求代码填充至左侧(所以实际上你自己并不用写 gql ),在左侧编辑区你可以删除/增加条件、字段、关联表内容,只拿自己想要的某个条件的某个字段。

请求的基本结构
# 查询
query 命令名($argumentname1:type) {
表名(where:{
字段1:{判断方法:判断值},
字段2:{判断方法:判断值},
... },
order_by:[{字段:排序方式}],
distinct_on:[去重字段],
limit:1) {
别名:需返回字段
}
}
- where 用来配置请求条件,是个对象类型
- order_by 用来配置排序条件,是个数组类型,数组中的内容是一个个对象
- distinct_on 用来设置去重条件,是个数组类型,数组中是去哪些字段的重
- limit 用来设置请求的数据条数,是个整数类型可以根据需求来删减需要返回的数据字段,返回的结果是一个对象
在 where 过滤条件中,任何值与空值进行比较时,结果总是为 true。
若要实现和空值比较时,返回 false,可以加一个条件数据:一旦为空,设置一个使条件不可能为 true 的值。
例1:像id = ${inputValue}
这个筛选,可加一个条件数据,当 inputValue 为空时,返回 -1。因为 id 均为正数,那么 id = -1 这个条件将永远为 false。
例2:像name = ${inputValue}
这个筛选,可加一个条件数据,当 inputValue 为空时,返回一个乱码 “vN4b䢡pZk9𪥝堒HwJ2Ƨ䚌rF7s”, 这个条件几乎不可能成立。
设置请求入参
- 在请求的「命令名」之后增加一对英文的(),然后在括号填写请求入参名称以及类型:$argumentname1:参数类型
- 在编辑界面左下方点击【VARVARLABES】展开参数编辑窗口,先写入一对,然后在花括号中写入参数的内容,参数内容中的参数名称依旧需要以美元符号 $ 开头,这里的参数是个对象,意味着如果你在命令名中配置了多个参数,在这里你就可以设置多个参数内容

运行请求
点击请求上方的【send query】按钮即可运行该请求,在右侧即可查看请求结果

Query 基本场景
- 根据过滤条件,获取一对一关联表中的数据:获取当前用户的个人信息
query getAccount($accountID: bigint) {
account(where: { id: { _eq:$accountID } }) {
id
profile {
id
name: ud_xingming_e1693e
gender: ud_xingbie_7644ed
phone_number: ud_shoujihaoma_e3188e
}
}
}
- 根据过滤条件,获取一对多关联表中的数据:获取这个活动在活动表中的报名记录,获取媒体—图片数据
# 请求某个活动的报名情况
query getsign_record($activityID: bigint) {
activity(where: {}, order_by: [{}], distinct_on: [id], offset: 1, limit: 1) {
id
name
image {
url
}
sign_record(where: { activity_id_activity: { _eq: $activityID } }) {
id
activity_id_activity
ud_account_id_zhanghu_999f9c
}
}
}
- 请求聚合数据:在文档中搜索“表名_aggregate”的 query 请求即可请求这张表的聚合数据
# 请求 reference 表的count,maxid
query getReferenceAggregate {
reference_aggregate {
aggregate {
count(columns:[id,content],distinct:true)
max {
id
}
}
}
- 请求关联表的 count 来对本表进行排序,并显示关联表的 count,比如要根据某个活动的报名数量对活动内容进行降序显示,并显示
# 请求 activity 表,让他按照报名表的count降序显示,并且显示报名数量
query activity_order_by_sign_count{
activity(order_by: [{sign_record_aggregate:{count:desc}}]) {
id
name
image{url}
sign_record_aggregate{
aggregate{count}
}
}
}
Mutation - insert 请求
搜索请求
在文档中搜索 insert_某张表名,找到这张表的 mutation 请求,点击该请求进入到请求的详细信息

添加请求
鼠标悬浮到最上方表名时,右侧可以点击 ADD QUERY,会自动将请求代码填充至左侧

请求的基本结构
#添加
mutation 命令名{
insert_表名(
objects:[{数据1字段1:赋值1,数据1字段2:赋值2},{数据2字段1:赋值1,数据2字段2:赋值2}],
on_conflict:{constraint:约束名,update_columns:[更新的字段1,更新的字段2],},
)
{
无所谓填啥,新手不用管,想研究的可以自行查看文档
}
}
- objects 用来填写需要插入的数据内容,是个数组类型,数组中每一条数据是一个对象
- on_conflict 用来填写发生数据冲突时,这个请求要做什么,是个对象类型,如果没有限制可以不配
- constraint:填写约束名称
- update_columns:填写冲突时,需要更新的字段名称### Mutation - update 请求
搜索/添加请求
在文档中搜索 update_某张表名,找到这张表的 mutation 请求,点击该请求进入到请求详情,添加请求与上述方法一致
请求的基本结构
#更新
mutation 命令名{
update_表名(
_set:{字段1:赋值1,字段2:赋值2},
_inc:{字段1:赋值1},
where:{字段1:{判断方法:判断值},字段2:{判断方法:判断值}}
)
{
无所谓填啥,新手不用管,想研究的可以自行查看文档
}
}
- _set 用来设置需要更新的字段以及内容,是个对象类型
- _inc 用来设置需要更新的数字类型的字段增加/减少一定的数值,增加则写正数,减少则写负数
- where 用来配置更新的条件,是个对象类型### Mutation - delete 请求
搜索/添加请求
在文档中搜索 delete_某张表名,找到这张表的 mutation 请求,点击该请求进入到请求详情 ,添加请求与上述方法一致
请求的基本结构
# 删除
mutation 命令名{
delete_表名(
where:{字段1:{判断方法:判断值},字段2:{判断方法:判断值}}
){
无所谓填啥,新手不用管,想研究的可以自行查看文档
}
}
-
where 用来配置删除数据的条件,是个对象类型# 在代码块中运行 API 前提:在 Zion 中添加并调试成功了API callThirdPartyApi(‘$operationId’, $args) : 调用Zion配置后API
-
$operationId: API id
-
$args: API 参数, 如
{'body':{"appKey": "f46dce7fa0566f0c"}}
context.callThirdPartyApi('$operationId', {'body'{"appKey": "f46dce7fa0566f0c","sign": "OTljNjYyNXXX=="}});
如何查找 API id: 在 Altair 的 Docs 的搜索框中输入:operation,然后会出现相关的请求,例如: operation_llw3pde2 中的 llw3pde2 就是 API id,当你配置了多个 API 时,这里也会出现多个请求,你可以通过点击这个请求,查看配置参数来确定具体是哪一个API

使用案例
- 通过小程序用户的account id获取其对应的微信union id 和 open id
常用场景:
- 服务号发送消息的时候需要指定用户的open id
- 当数据源在外部时(比如明道云),需要保存open id作为用户标识
- 当一个企业有多个小程序,要共用同一套体系的时候,会用到union_id. 比如为了向用户持续推送消息,需要用到公众号推送,启用这个功能需要用到union_id.入参:用户的account id (整数类型) 出参:微信union id (文本类型)和 open id (文本类型)
// 获取account_id
const account_id = context.getArg('account_id')
console.log(account_id)
// 取account信息的gql语句(入参为account id,即过滤的条件)
var gql = `query queryAccount($account_id:bigint!)
{
account (where:{id:{_eq:$account_id}})
{
id
oauth2_user_info_map
}
}`
// 执行这个gql语句,得到查询结果
var result_id = context.runGql(
'queryAccount',
gql,
{ account_id },
{ role: 'user' }
)
// 创建数组a, a为account信息里名为account的数组
var a = []
a = result_id.account
//情况1,account既有union_id,也有open_id
if (
a.length != 0 &&
a[0].oauth2_user_info_map.WECHAT.hasOwnProperty('unionId')
) {
var open_id = a[0].oauth2_user_info_map.WECHAT.openId
var union_id = a[0].oauth2_user_info_map.WECHAT.unionId
context.setReturn('union_id', union_id)
context.setReturn('open_id', open_id)
}
// 情况2,account只有open_id, 没有union_id
else if (
a.length != 0 &&
!a[0].oauth2_user_info_map.WECHAT.hasOwnProperty('unionId')
) {
var open_id = a[0].oauth2_user_info_map.WECHAT.openId
context.setReturn('union_id', '')
context.setReturn('open_id', open_id)
}
// 情况3,account既没有open_id也没有union_id
else {
context.setReturn('union_id', '')
context.setReturn('open_id', '')
}
- 在代码块中调用API获取图片URL,转存到Zion
基本逻辑: 通过第三方API获取到图片的URL,利用 Zion 内置的 uploadMedia 方法将URL解析为图片并保存在Zion 中,定义一个往你的项目中 insert 或者 update 数据的 gql ,其中入参为 uploadMedia 方法返回的 id,运行该 gql 即可将图片存到项目的数据库中 uploadMedia(‘url’, ‘headers’) 参数 url : 从API 获取过来的 URL insert的代码:
const url = '' // 过来的 url 链接
const headers = {}
const media = context.uploadMedia(url, headers) // $url: 图片地址; $headers: 请求需要的headers, 一般都填{},除非你是向非本项目的数据库传文件。
// 返回值举例:{mediaType:"IMAGE", id:1020000000000003}
const imageID = media.id
const gql = `mutation inset_image($imageID: bigint){
insert_表名(
objects:[{图片字段_id:$imageID}])
{
returning{id}
}
}`
context.runGql('inset_image', gql, { imageID }, { role: 'admin' })
update的代码:
const xx_id = context.getArg('xx_id') //获取过滤用的表id
const url = '' // 过来的 url 链接
const headers = {}
const media = context.uploadMedia(url, headers) // $url: 图片地址; $headers: 请求需要的headers, 一般都填{},除非你是向非本项目的数据库传文件。
// 返回值举例:{mediaType:"IMAGE", id:1020000000000003}
const imageID = media.id
const gql = `mutation update_image($imageID: bigint,$xx_id:bigint){
update_表名(
_set:{图片字段_id:$imageID}
where:{id:{_eq:$xx_id}})
{
returning{id}
}
}`
context.runGql('update_image', gql, { imageID, xx_id }, { role: 'admin' })