值表达式 (Value Expressions)
最后更新:2026年7月20日
在 Script 中,凡是需要值的位置(URL、请求 body、字段值、条件、筛选值、目标 id 等)都是下面三种形态之一。本文档说明这三种形态、值来自何处(上下文根),以及 WEEGLOO 数据特有的 Locale 映射规则。Statement 目录中的所有字段都遵循此规则。
三种形态
| 形态 | 规则 | 示例 |
|---|---|---|
| 引用 (reference) | 在上下文中解析字符串内的 { /json-pointer }。 | "{ /payload/fields/title }" |
| 字面量 (literal) | 不含 { /ptr } 的值(字符串、数字、布尔值、对象、数组)。原样使用。 | "draft", 42, true, { "a": 1 } |
| 运算与条件 (JsonLogic) | 以单个运算符作为键的对象。操作数本身又是值表达式(引用、字面量、嵌套)。 | { "+": [ "{ /vars/n }", 1 ] } |
这三种形态可以嵌套:在 JsonLogic 操作数中放入引用,把引用的结果再放入运算,即可这样组合。
引用:{ /json-pointer }
在花括号内放入 RFC 6901 JSON Pointer(必须以 / 开头)。花括号周围允许有空格({ /a/b } 与 {/a/b} 相同)。
单一指针与混合模板:类型规则
- 当整个字符串是单一指针时,会保持该值的原始类型(数字则数字,对象则对象,数组则数组)。
- 与字面量文本混合时,会拼接(concatenation)为字符串。
"{ /payload/fields/count }" // 若为数字值则保持数字原样(例如 42)
"{ /payload/fields/tags }" // 若为数组则保持数组原样
"page-{ /payload/fields/n }-of-10" // 字符串拼接 → "page-42-of-10"
"Bearer { /payload/fields/token }" // 字符串拼接 → "Bearer abc123"缺失值与转义
- 当路径不存在或值为空时,单一指针会作为
null处理,混合模板会作为空字符串处理。 - 若要把
{当作字面量使用,请用\{转义(该位置不会被解释为指针)。
上下文根:值从何而来
{ /pointer } 的顶层段是下面五种之一。
| 根 | 内容 |
|---|---|
/payload | 调用时传入的 JSON payload(输入)。例如:{ /payload/fields/email } |
/headers | 调用时传入的请求 HTTP 头。键为小写,每个名称对应单个值。例如:{ /headers/authorization } |
/<name> | 带有 name 的前置 statement 的结果。例如:{ /order/sys/id } |
/vars/<name> | 用 SetVar 声明的 script-scoped 可变变量。例如:{ /vars/total } |
/error | 仅在 Try 的 catch 块内使用。即捕获到的错误 { message, statement }。例如:{ /error/message } |
statement 结果的形态
带有 name 的 statement,其结果形态因类型而异。
| statement | 结果形态 | 引用示例 |
|---|---|---|
Http | { status, body } | { /resp/status }, { /resp/body/choices/0/message/content } |
ResourceCreate、ResourceRead(单条)、ResourceFind(单条) | 资源本身 | { /post/sys/id }, { /post/fields/title/en-US } |
ResourcePageRead | { items, next } | { /page/items/0/sys/id }, { /page/next } |
ResourceFind在没有匹配时绑定null。用{ "==": [ "{ /found }", null ] }来分支判断是否存在。ResourceRead(单条)在目标不存在时会报错(可用Try处理)。详情参见 Statement 目录的资源读取。
运算与条件:JsonLogic
需要计算或条件时,使用 jsonlogic.com 规范中的运算符对象。
- 数据访问统一使用
{ /ptr }引用,而非原生的var(dot-path)写法。引擎先解析操作数中的指针,再应用运算符。 - 单键对象的键如果是已注册的运算符,就当作运算处理;否则当作普通对象。
运算符表
| 分类 | 运算符 | 含义与示例 |
|---|---|---|
| 条件 | if(别名 ?:) | { "if": [条件, 真值, 条件2, 真值2, …, 默认值] }。取第一个为真的条件对应的值;若都不满足,则取最后的默认值。 |
| 逻辑 | and、or | 短路求值。and 返回第一个 falsy(或最后一个),or 返回第一个 truthy(或最后一个),并以其值本身返回。 |
| 逻辑 | ! (not)、!! (to-bool) | { "!": x } 是对 truthy 取反,{ "!!": x } 是判断是否 truthy。存在性检查常用 !!。 |
| 相等 | ==、!= | 宽松比较(强制转换为数字后比较。"1"==1 为真)。 |
| 相等 | ===、!== | 严格比较(连类型也比较)。 |
| 比较 | <、<=、>、>= | 可链式:{ "<": [1,2,3] } 即 1<2 AND 2<3。无法数字化(NaN)时为 false。 |
| 算术 | + | 所有操作数之和。 |
| 算术 | - | 一个操作数时取负,两个操作数时做减法。 |
| 算术 | *、/、% | 乘、除、取余。 |
| 聚合 | min、max | 操作数的最小值、最大值。 |
| 字符串 | cat | 把所有操作数拼接成字符串。 |
| 包含 | in | { "in": [needle, haystack] }。haystack 是字符串时判断子字符串,是集合时判断元素包含。 |
| 数组 | merge | 把多个数组或值扁平化为一个数组(用于累积收集)。 |
不支持数组遍历运算符(map、filter、reduce、all、some、none)。Script 通过 Loop 遍历数组(参见 Statement 目录的 Loop)。
数字转换与示例
数字转换规则如下。数字保持原样,true 转为 1,false 转为 0,字符串会被解析(无法解析则为计算失败值),null 转为 0。
{ "-": [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] } // 余额 - 费用
{ "<": [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] } // 余额 < 费用 → boolean
{ "and": [ { "<": [ "{ /a/body/risk }", 0.5 ] }, { ">=": [ "{ /b/body/score }", 700 ] } ] }
{ "cat": [ "id-", "{ /payload/sys/id }" ] } // "id-<uuid>"
{ "!!": "{ /found/sys/id }" } // 存在则为 true
{ "merge": [ "{ /vars/ids }", [ "{ /row/sys/id }" ] ] } // 向数组累积一个元素
{ "if": [ "{ /page/next }", "{ /page/next }", "END" ] } // 有 next 则取 next,没有则取 "END"真假判定 (Truthiness)
if、and、or、!、!! 以及 If.condition、Loop.while 按以下规则判定真假。
- falsy:
null、false、数字0、空字符串""、空集合(空数组)。 - truthy:其余全部(非 0 的数字、非空的字符串和数组、所有对象)。
键也可以引用
像 fields 这样的映射,其键也支持 { /ptr } 引用。键会在运行时解析。
"fields": { "{ /payload/fields/fieldName }": { "en-US": "{ /payload/fields/fieldValue }" } }如果两个键解析为相同的值,就会发生冲突并导致引擎报错。
Locale 映射 (LocaleValueMap):Content 与 Media 特有的规则
WEEGLOO Content 与 Media 的每个字段都不是单一值,而是按 Locale 划分的映射(例如 balance 为 { "en-US": 1, "ko-KR": 10 })。因此读写时必须连同 Locale 一起处理。Media 同样,其 title 和 description(标量)、file(摄取指令)都是 Locale 映射。像 /payload 或 HTTP 响应这类并非 Content 或 Media 的 JSON 则与此规则无关(保持 schema 所定义的结构,是标量就是标量)。
读取
- 要取得标量,需连 Locale 一起指定:
{ /<name>/fields/<field>/<locale> }(例如{ /post/fields/title/en-US })。 - 不带 Locale 时,
{ /<name>/fields/<field> }会返回 Locale 映射的整个对象。 localized:false字段只存在于默认 Locale 存储桶中,因此用该默认 Locale 代码来读取。
写入 (ResourceCreate、ResourceUpdate、ResourcePatch 的 fields)
值是按 Locale 划分的映射 { "<locale>": <标量值表达式> }。与读取对称。
"fields": {
"title": { "en-US": "Hello", "ko-KR": "안녕" }, // 多个 Locale 就并列存储桶
"status": { "en-US": "paid" }
}ResourceCreate必须在所有要填充的字段中都包含 Space 默认 Locale 存储桶(default-locale 规则)。ResourceUpdate是整体替换。fields中不存在的字段和 Locale 会被移除(包括 file)。ResourcePatch只更新指定的字段和存储桶(其余字段和 Locale 保持不变)。- 用字面量
null删除:当值为字面量null时,会删除该 (field, locale) 存储桶(这是在 Patch 中清空特定 Locale 的标准做法)。""(空字符串)不是删除,而是设置为空值。值表达式({ /ptr })在运行时求值为 null 时不是删除,而是报错(不会静默吞掉 payload 的缺失)。删除只适用于字面量null。 Media的file:值不是标量,而是摄取指令{ "source": …, "encoding": "url"|"base64" }。包含文件的写入仅限 Async(参见 Statement 目录的 ResourceCreate)。localized:false字段只放入默认 Locale 存储桶。- Locale 代码(映射的键)也可以用
{ /ptr }引用(参见上文 键也可以引用)。用于创建动态 Locale。
locale 便利字段
在 ResourceCreate、ResourceUpdate、ResourcePatch 中提供 locale 时,引擎会自动把 fields 的每个值包装成 { <locale>: 值 } 存储桶。 也就是说只需提供标量即可。
// 下面两个是等价的
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
"locale": "en-US", "fields": { "title": "Hello" } }
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
"fields": { "title": { "en-US": "Hello" } } }如果在提供 locale 的同时又在值中嵌套了 Locale 映射({ "en-US": … }),就会变成 { <locale>: { "en-US": … } } 这样的双重嵌套(属于作者失误)。请统一为:用 locale 时只写标量,不用时只写显式的 Locale 映射。
where 与 order 中的 Locale
- 在
where和order中,fields.X的 Space 默认 Locale 会被引擎自动应用(与 CMA 查询一致)。 - 要针对特定 Locale,请用
fields.X.<locale>明确指定。
"where": { "fields.slug": { "eq": "{ /payload/fields/slug }" } } // 默认 Locale 的 slug
"where": { "fields.title.ko-KR": { "prefix": "안" } } // 特定 Locale相关文档
- Statement 目录:使用值表达式的 17 种 statement 的字段与结果。
- 执行语义、约束、安全:执行顺序、错误、乐观锁、静态约束。
- Cookbook:组合值表达式的完整示例。
- Script 概览:顶层结构与执行模式。
