Statement 目录

最后更新:2026年7月23日

statements 数组的每个元素都是一个语句(statement)。本文整理了 17 种语句的字段、行为与结果。所有取值位置都遵循值表达式的规则(引用、字面量、JsonLogic、Locale 映射)。

语句概览

分类type一句话概要
资源写入ResourceCreate创建 Content/Media(可选择发布)
ResourceUpdate整体替换 Content/Media 字段(未提供的 field·locale 会被删除)
ResourcePatch部分合并 Content/Media 字段(仅指定的 field·locale;字面量 null 表示删除)
ResourceDelete删除(仅 Draft·Archived;若为 Published 需先 unpublish)
ResourcePublish / ResourceUnpublish发布 / 取消发布
ResourceArchive / ResourceUnarchive归档 / 取消归档
资源读取ResourceRead按 id 单条查询
ResourceFind按过滤条件返回首个匹配的单条(无则为 null)
ResourcePageRead过滤/排序/分页查询({ items, next }
外部Http外部 HTTP 调用({ status, body })。仅限 Async
变量SetVar声明/更新 script 作用域变量
控制流If条件分支
Loop循环(foreach / while / counted)
Parallel分支并发执行
Return返回结果并提前结束
Try异常处理(catch/finally)

循环调用最多 3 次。 上面的资源写入语句(ResourceCreateResourceUpdateResourcePublish 等)会触发变更事件,而这些事件可能通过 Webhook 再次运行 Script。这样的链条(Script → 事件 → Webhook → Script → …)最多只持续 3 次,超过后平台会自动中断以防止无限循环。

公共字段

{ "type": "<StatementType>", "name": "<可选,script 内唯一>", /* ...各类型专属字段... */ }
  • type:判别符。取上表中的某个值(必填)。
  • name:可选。指定后,结果会以 /<name> 绑定到上下文,后续 statement 可通过 { /<name>/... } 引用。若不使用结果则可省略。
  • 绑定名称规则name(以及 Loopas)是直接叠加到上下文根上的键,因此在保存时会被校验。它不能为空字符串,不能包含 /·~(须可用作 JSON Pointer 键),不能与保留根(payload·vars·error)相同,且在同一个 Script 内必须唯一。违反时会分别以 WGL400033(格式)·WGL400032(保留字)·WGL400034(重复)拒绝保存。

实体引用形态

contentTypetarget 等实体引用统一为 { "sys": { "id": <值表达式> } } 一种形态。只需 sys.id,目标类型由 resource 推断(sys.typesys.targetType 均省略)。

  • contentType.sys.id 通常是字面量(例如 "ct_post")。
  • target.sys.id 通常是 { /ptr } 值表达式(运行时 resolve,例如 { /payload/sys/id })。

resource

资源类语句通过 resource: "Content" | "Media" 指定目标种类。

资源写入

所有写入语句都带有 propagateEvents(默认 false)。设为 true 时,该写入会发布自身的 EntityEvent(触发搜索索引、Webhook 等后续动作)。默认不发布(静默的系统写入)。

ResourceCreate

创建 ContentMediaContentMedia 共享 fields 模型,值为 Locale 映射。

字段目标说明
resource通用"Content""Media"(必填)
contentTypeContent要创建的 Content Type{ sys: { id } })。resource 为 Content 时必填
fields通用字段映射 { "<field>": { "<locale>": 值 } }。每个填充的字段都必须包含默认 Locale 桶。Content 的键遵循 Content Type 定义,Media 的键是固定的(title·description·file
locale通用(便捷项)提供后会将 fields 的各个值自动包装为 { <locale>: 值 }
publish通用写入后发布(在 CDA/ACDA 上可见)。默认 true
  • Media filefields.file.{locale} 的值是摄取指令 { "source": <值表达式>, "encoding": "url"|"base64" }(两者均必填)。包含文件的 Media 写入仅限 Async(在后台由引擎内联处理后发布,url 与 base64 通用)。也可以创建不含文件(fileless)的 Media。若 publish:true 但没有文件或处理未完成,则会在发布阶段报错;若 publish:false 则保持 Draft
  • 结果name 绑定):创建出的资源。{ /<name>/sys/id }{ /<name>/fields/<field>/<locale> }
// Content
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
  "fields": { "title": { "en-US": "{ /payload/fields/title }" } }, "publish": true, "name": "post" }
 
// Media。file 是摄取指令(仅限 Async)
{ "type": "ResourceCreate", "resource": "Media",
  "fields": {
    "title": { "en-US": "{ /payload/fields/prompt }" },
    "file":  { "en-US": { "source": "{ /gen/body/data/0/url }", "encoding": "url" } }
  }, "name": "img" }

ResourceUpdate

对目标 ContentMedia 的字段进行整体替换(PUT)。fields 中给出的内容会原样成为新字段,这里未列出的 field 与 locale 会被清除。若只想改动一部分,请使用 ResourcePatch

字段说明
resource"Content""Media"
target目标({ sys: { id } },必填)。id 通常为 { /ptr }
fields写入的全部字段。值为 Locale 映射。因为是整体替换,这里未列出的 field 与 locale 会被移除。Media file 是摄取指令(参见上文 ResourceCreate)。列出的文件总是重新摄取,未提供的 locale 文件会被删除
locale(便捷项)自动包装 fields
version(可选)值表达式(Int)。乐观锁。提供后,仅当与目标当前的 sys.version 一致时才更新;不一致则以版本冲突错误 abort(可用 Try catch)。省略时不做检查(last-write-wins)
publish更新后 republish。默认 true

Media 上若仅为修改 metadata 而使用 Update,会因缺少 file 而导致文件全部被删除(因为是整体替换)。部分变更请务必使用 ResourcePatch。包含文件的 Update 仅限 Async。

{ "type": "ResourceUpdate", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } },
  "fields": { "title": { "en-US": "Hello", "ko-KR": "안녕" }, "status": { "en-US": "published" } } }

ResourcePatch

对目标 ContentMedia 的字段进行部分合并(PATCH)。只覆盖 fields 中给出的字段(及其中的 Locale),而未提及的字段与 Locale 保持不变。值形态、localeversionpublishResourceUpdate 相同。

字段说明
resource"Content""Media"
target目标({ sys: { id } },必填)。id 通常为 { /ptr }
fields要覆盖的字段。值为 Locale 映射。仅更新指定的字段与 Locale 桶(其余保持不变)。若值为字面量 null,则删除该 (field, locale)。Media file 是摄取指令(参见上文 ResourceCreate)
locale(便捷项)自动包装 fields
version(可选)与 ResourceUpdate 相同(乐观锁)
publish更新后 republish。默认 true
  • 删除特定 Locale 或文件:将值设为字面量 null。例如 "title": { "fr-FR": null }(删除 fr-FR 标题)、"file": { "en-US": null }(删除 en-US 文件)。值表达式在运行时求值为 null 并不会删除,而是报错(只有字面量 null 才会删除)。
  • 若对 Media file 给出摄取指令,则会替换该 locale 的文件(仅限 Async)。不提供文件则保持不变。
// 仅将 viewCount(en-US) +1。title、其他 locale 等其余内容保持不变
{ "type": "ResourcePatch", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } },
  "fields": { "viewCount": { "en-US": { "+": [ "{ /payload/fields/viewCount }", 1 ] } } } }

ResourceDelete

删除目标。DraftArchived 状态可以删除。若为 Published 或 Changed 会被拒绝,因此必须先 ResourceUnpublishMedia 在文件处理中(busy)时会被拒绝)。不会 auto-unpublish(与 CMA/ACMA 相同)。

字段说明
resource"Content""Media"
target目标({ sys: { id } },必填)
{ "type": "ResourceDelete", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } } }

ResourcePublish, ResourceUnpublish, ResourceArchive, ResourceUnarchive

独立控制目标的发布与归档状态。四者的字段完全相同。各操作的 status 前提条件与 CMA/ACMA 相同(publish 不能用于 Archived 且需文件处理完成,unpublish 仅限 Published·Changed,archive 仅限 Draft,unarchive 仅限 Archived)。

字段说明
resource"Content""Media"
target目标({ sys: { id } },必填)
version(可选)值表达式(Int)。乐观锁。提供后仅当与当前 sys.version 一致时才执行
{ "type": "ResourcePublish",   "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } } }
{ "type": "ResourceUnpublish", "resource": "Content", "target": { "sys": { "id": "{ /payload/sys/id }" } } }
{ "type": "ResourceArchive",   "resource": "Media",   "target": { "sys": { "id": "{ /m/sys/id }" } } }

资源读取

读取语句不改变状态(没有 propagateEvents)。

这三种读取语句都通过 from(可选,默认 Current)来决定读取哪一份存储版本。Current 是内容工作室所看到的最新草稿(CMA/ACMA 读取的值),Published发布快照(CDA/ACDA 所传递的、最后一次发布时刻的值)。

ResourceFindResourcePageRead 在此基础上还可以通过 advanced(可选,默认 false)开启高级搜索(Advanced Search)。它仅限 Content,因此在 Media 读取中会被忽略。开启时,where 可使用 regexnearwithin 运算符与全文检索(对已开启全文检索的 LongText 字段,eq 还能通过部分、近似匹配找到包含该值的项目),且 order 可按 fields.* 排序。关闭时,这三个运算符会被拒绝,文本的 eq 为精确匹配,而 prefix 及比较、列表运算符与高级搜索无关,始终可用。刚刚创建或修改的项目,需要短暂片刻(约 1 秒)才会反映到高级搜索中,因此紧接着的下一次高级搜索查询可能查不到它。若需立即读取刚写入的项目,请按 id 使用 ResourceRead(基本存储版本,无反映延迟),或用写入返回的 sys.id 查询。

whereorder 中,内容字段要写成 fields.<field>(仅凭字段名本身无法识别)。fields.<field>Space 默认 Locale 会被自动应用,因此无需直接附加 Locale。下方示例中的 fields.statusfields.slug 就是默认 Locale 查询。只有在需要针对特定(非默认)Locale 时,才用 fields.<field>.<locale>(例如 fields.title.ko-KR)明确指定。sys.*(如 sys.createdAt)与 createdBy:self)则不加 fields.,直接书写。详细规则见值表达式的 where 与 order 中的 Locale

ResourceRead

id 单条查询(get-by-id)。结果会将整个资源绑定到名称上。

字段说明
resource"Content""Media"
target目标({ sys: { id } })。id 为值表达式
from(可选)Current(默认,最新草稿)或 Published(发布快照)
  • 结果:直接引用 { /<name>/sys/id }{ /<name>/fields/<field>/<locale> }(无需 items/0)。
  • 目标不存在时报错。可用 Try 包裹处理。
{ "type": "ResourceRead", "resource": "Content",
  "target": { "sys": { "id": "{ /payload/fields/orderId }" } }, "name": "order" }

ResourceFind

读取按过滤条件匹配的首个单条若无则为 null。用于以唯一业务键(slug、email、sku)查找单条记录时。

字段说明
resource"Content""Media"
contentType(Content)检索范围 Content Type{ sys: { id } }
where过滤条件({ "<field>": { "<op>": <值> } })。可用运算符遵循运算符列表regex/near/within 需要 advanced)。支持 createdBy: ":self"
order在多个匹配时决定“第一个”的排序(例如 "-sys.createdAt"
from(可选)Current(默认,最新草稿)或 Published(发布快照)
advanced(可选)通过高级搜索(Advanced Search)执行。仅限 ContentMedia 忽略)。默认 false。参见上文 资源读取 说明
  • 结果:将首个匹配的资源绑定到名称上。可通过 { /<name>/fields/<field>/<locale> } 直接引用。若无则为 null,因此可用 { "==": [ "{ /<name> }", null ] } 判断是否存在来分支(find-then-upsert 的典型做法)。
{ "type": "ResourceFind", "resource": "Content", "contentType": { "sys": { "id": "ct_article" } },
  "where": { "fields.slug": { "eq": "{ /payload/fields/slug }" } }, "name": "found" }

ResourcePageRead

过滤、排序、分页查询。

字段说明
resource"Content""Media"
contentType(Content)检索范围 Content Type
where过滤条件({ "<field>": { "<op>": <值> } })。可用运算符遵循运算符列表regex/near/within 需要 advanced)。支持 createdBy: ":self"
order排序(例如 "-sys.createdAt"
limit分页大小(不超过 100)
cursor下一页使用上次结果的 next
from(可选)Current(默认,最新草稿)或 Published(发布快照)
advanced(可选)通过高级搜索(Advanced Search)执行。仅限 ContentMedia 忽略)。默认 false。参见上文 资源读取 说明
  • 结果{ items, next }{ /<name>/items/0/... },下一页为 { /<name>/next }
  • 完整遍历通过 Loop while "{ /vars/hasMore }" 配合 cursorSetVar 累加来实现(参见烹饪书)。
{ "type": "ResourcePageRead", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
  "where": { "fields.status": { "eq": "draft" } }, "order": "-sys.createdAt", "limit": 100, "name": "page" }

外部

Http

调用外部 HTTP。只要存在 HttpexecutionMode 就必须是 AsyncExternalIo)。

字段说明
method"GET""POST""PUT""PATCH""DELETE"
url目标 URL(值表达式,可插入 { /ptr }
headers[{ "key", "value", "secret"? }]value 为值表达式。secret:true 的请求头被视为 CMA(管理员)专用,不会向最终用户暴露,且仅在发送前才解密
body请求 body(值表达式或 JSON)
timeoutMs本次调用的超时时间(ms)
retry响应 status 大于等于 400 时的重试次数。默认 0,上限为 maxHttpRetry(默认 2)
ignoreStatusCode(重试结束后的)最终 status 大于等于 400 时是否将本次调用视为失败。默认 false 时会按失败处理,成为 Try/catch 的对象。为 true 时则不视为失败,而是将 { status, body } 原样绑定(由调用方自行按 status 分支)
  • 结果{ status, body }{ /<name>/status }{ /<name>/body/... }
  • 响应大小上限:响应 body 最大为 10MiB。超过时本次调用会以异常失败,可像其他运行时失败一样用 Try/catch 处理(这是基于大小的失败,因此不会被 ignoreStatusCode 忽略)。
{ "type": "Http", "method": "POST", "url": "https://api.llm.com/v1/gen",
  "headers": [ { "key": "Authorization", "value": "Bearer sk-...", "secret": true } ],
  "body": { "prompt": "{ /payload/fields/prompt }" }, "timeoutMs": 15000, "retry": 1, "name": "resp" }

变量

SetVar

声明或更新 script 作用域的可变变量。通过 { /vars/<var> } 引用(JsonLogic 本身没有变量声明,因此作为 statement 提供)。

字段说明
var变量名。通过 { /vars/<var> } 引用
value值表达式。可引用自身以进行累加
{ "type": "SetVar", "var": "total", "value": 0 }
{ "type": "SetVar", "var": "total", "value": { "+": [ "{ /vars/total }", "{ /row/qty }" ] } }   // 累加
{ "type": "SetVar", "var": "ids",   "value": { "merge": [ "{ /vars/ids }", [ "{ /row/sys/id }" ] ] } }  // 收集数组

控制流

If

条件分支。condition 是 JsonLogic,真与假遵循真值判定的规则。

字段说明
conditionJsonLogic(求值为 boolean)
then为真时执行的 Statement 数组
else(可选)为假时执行的 Statement 数组
{ "type": "If",
  "condition": { "<": [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] },
  "then": [ { "type": "Return", "value": { "ok": false, "reason": "insufficient credit" } } ],
  "else": [ /* ... */ ] }

Loop

循环。选择一种模式over(foreach)、while(条件)、for(计数)。无论哪种模式,引擎都会以 maxIterations 强制上限(防止无限循环)。body 内禁止外部调用(HttpMedia 文件摄取)

字段说明
overforeach:resolve 为数组的值表达式
while条件:JsonLogic(为真时持续循环)
for计数:{ "from", "to", "step"? }。从 fromto含两端),step 默认 1
maxIterations引擎强制的最大循环次数(必填)
as用于绑定当前项或索引的名称({ /<as> }
body循环体 Statement 数组
// foreach
{ "type": "Loop", "over": "{ /payload/fields/items }", "as": "item", "maxIterations": 100,
  "body": [ { "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_item" } },
             "fields": { "name": { "en-US": "{ /item/name }" } } } ] }
 
// while
{ "type": "Loop", "while": "{ /vars/hasMore }", "maxIterations": 1000, "body": [ /* ... */ ] }
 
// counted (1..10 step 2)
{ "type": "Loop", "for": { "from": 1, "to": 10, "step": 2 }, "as": "i", "maxIterations": 100, "body": [ /* ... */ ] }

Parallel

并发执行各分支,join 后再继续。分支之间不可相互引用(若存在依赖,请改为顺序排列)。

字段说明
branchesStatement[][]。每个元素为一个分支(语句数组)
{ "type": "Parallel", "branches": [
  [ { "type": "Http", "method": "GET", "url": "https://api.a.com/x", "name": "a" } ],
  [ { "type": "Http", "method": "GET", "url": "https://api.b.com/y", "name": "b" } ]
] }

Return

相当于一般编程中的 return Script 的结果返回给调用方,并在该处正常结束

字段说明
value(可选)要返回的值表达式
isError默认 false。为 true 时,value 会作为响应的 error 输出(否则为 return
statusCode响应状态码。默认 200
  • 若未到达 Return,则没有返回值。要给出结果,请显式指定 value
  • 它是正常结束,而非异常或 throw,因此不属于 catch 的对象(即使在 Try 内,也会结束整个 Script,但仍会执行 finally)。
  • guard 也用该语句表达。即 Ifthen:[Return](违反条件时返回,之后不再执行),这只是其众多用途之一。
{ "type": "Return", "value": { "orderId": "{ /order/sys/id }", "status": "paid" }, "statusCode": 201 }
{ "type": "Return", "value": { "reason": "payment failed" }, "isError": true, "statusCode": 402 }

Try

异常处理。

字段说明
body要尝试执行的 Statement 数组
catch(可选)body 失败时执行。在 /error 中暴露 { message, statement }
finally(可选)无论成功或失败始终执行
  • catch 处理了错误,则 Script 不会中断。只有没有 catch 的失败才会中断 Script(包括补偿尝试)。
  • 什么算“失败”,以及补偿(compensation)的限制,详见执行语义、约束与安全
{ "type": "Try",
  "body":    [ { "type": "Http", "method": "POST", "url": "https://primary.api/gen", "name": "resp" },
               { "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_result" } },
                 "fields": { "text": { "en-US": "{ /resp/body/text }" } } } ],
  "catch":   [ { "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_result" } },
                 "fields": { "text": { "en-US": "生成失败" }, "error": { "en-US": "{ /error/message }" } } } ],
  "finally": [ /* 始终执行 */ ] }