writing-handlebars

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
<!-- TIER:1 -->
<!-- TIER:1 -->

Writing Handlebars Expressions

编写Handlebars表达式

Handlebars is Celigo's template language for embedding dynamic values into resource configurations. Any string field that the platform evaluates at runtime can contain Handlebars expressions.
Concerns when writing Handlebars:
  • Context -- where the expression runs determines what data is available and how output is treated
  • Braces -- double
    {{ }}
    vs triple
    {{{ }}}
    controls output escaping
  • Field access --
    record.
    prefix in all contexts (AFE 2.0),
    @root
    for job/settings/connection, bracket notation for special characters
  • Helpers -- 79 custom helpers for math, string manipulation, dates, encoding, regex, and more
  • Block helpers --
    #each
    ,
    #if
    ,
    #compare
    ,
    #with
    for iteration and conditional logic
  • Date/time -- moment.js format tokens with timezone support
Used across exports, imports, mappings, output filters, and APIs.
Handlebars是Celigo用于在资源配置中嵌入动态值的模板语言。平台在运行时评估的任何字符串字段都可以包含Handlebars表达式。
编写Handlebars表达式时需要注意的事项:
  • 上下文——表达式的运行位置决定了可用的数据以及输出的处理方式
  • 花括号——双
    {{ }}
    与三
    {{{ }}}
    控制输出是否转义
  • 字段访问——在所有AFE 2.0上下文中使用
    record.
    前缀,通过
    @root
    访问任务/设置/连接,使用方括号语法处理含特殊字符的字段
  • 辅助函数——79个自定义辅助函数,涵盖数学运算、字符串处理、日期操作、编码、正则表达式等功能
  • 块级辅助函数——
    #each
    #if
    #compare
    #with
    用于循环和条件逻辑
  • 日期/时间——支持时区的moment.js格式标记
适用于导出、导入、映射、输出过滤器和API等场景。

Where Handlebars Are Used

Handlebars的适用场景

Mapping extracts

映射提取

In import
mappings[].extract
fields, Handlebars concatenates, transforms, or conditionally selects values. The context is the current record.
在导入的
mappings[].extract
字段中,Handlebars用于拼接、转换或条件选择值。上下文为当前记录。

HTTP request templates

HTTP请求模板

Export and import
http
blocks use Handlebars in
relativeURI
,
body
,
headers
, and
postBody
. Triple braces are essential to avoid HTML encoding of query parameters and JSON.
导出和导入的
http
块在
relativeURI
body
headers
postBody
中使用Handlebars。三花括号对于避免查询参数和JSON的HTML转义至关重要。

RDBMS SQL queries

RDBMS SQL查询

SQL queries in
rdbms.query
use Handlebars with the mandatory
record.
prefix. Triple braces prevent encoding of SQL-significant characters like commas and quotes. For full SQL patterns (MERGE, upsert, bulk operations, dialect differences), see writing-sql.
rdbms.query
中的SQL查询使用Handlebars,且必须带有
record.
前缀。三花括号可防止SQL关键字符(如逗号和引号)被转义。如需完整SQL模式(MERGE、upsert、批量操作、方言差异),请参阅writing-sql

Output filters

输出过滤器

Expression-based filters on exports use Handlebars to evaluate whether a record passes through or gets skipped.
导出中基于表达式的过滤器使用Handlebars评估记录是否通过或被跳过。

File paths and names

文件路径和名称

Dynamic file names in FTP/S3 exports and imports use Handlebars for timestamps and record-derived values.
FTP/S3导出和导入中的动态文件名使用Handlebars生成时间戳和基于记录的值。

Delta tokens

Delta令牌

Platform-injected variables like
{{{lastExportDateTime}}}
provide the last successful export timestamp for incremental syncs. These are not record fields -- the platform injects them at runtime into the export's HTTP/query context only.
平台注入的变量(如
{{{lastExportDateTime}}}
)提供上次成功导出的时间戳,用于增量同步。这些不是记录字段——平台仅在运行时将其注入导出的HTTP/查询上下文。

Quick Reference

快速参考

Context Decision Matrix (AFE 2.0)

上下文决策矩阵(AFE 2.0)

All contexts use
record.
prefix to access the current record's fields (AFE 2.0). Do NOT use bare field names,
data.field
, or
data.0.field
-- those are deprecated AFE 1.0 patterns. Exception: Mapper 1.0 (Salesforce/NetSuite) uses bare field names without
record.
prefix.
WhereSyntaxData prefixExample
Mapping extract
{{ }}
(double)
record.
{{record.firstName}}
HTTP relative URI
{{{ }}}
(triple)
record.
{{{record.orderId}}}
in URI
HTTP body / postBody
{{{ }}}
(triple)
record.
{{{record.orderId}}}
in JSON body
SQL query (RDBMS)
{{{ }}}
(triple)
record.
{{{record.email}}}
in WHERE clause
Output filter
{{ }}
(double)
record.
{{record.status}}
Delta URI parameter
{{{ }}}
(triple)
(platform-injected)
{{{lastExportDateTime}}}
Additional context objects available via
@root
:
ObjectDescription
record
Current record being processed
job
Current job metadata
settings
Integration/flow settings
connection
Connection object (for auth headers)
When one-to-many grouping is configured, the data shape changes to
batch_of_records
-- iterate with
{{#each batch_of_records}}
to access individual records.
所有上下文均使用
record.
前缀访问当前记录的字段(AFE 2.0)。请勿使用裸字段名、
data.field
data.0.field
——这些是已弃用的AFE 1.0模式。**例外:**Mapper 1.0(Salesforce/NetSuite)使用不带
record.
前缀的裸字段名。
使用场景语法数据前缀示例
映射提取
{{ }}
(双花括号)
record.
{{record.firstName}}
HTTP相对URI
{{{ }}}
(三花括号)
record.
URI中的
{{{record.orderId}}}
HTTP请求体/postBody
{{{ }}}
(三花括号)
record.
JSON请求体中的
{{{record.orderId}}}
SQL查询(RDBMS)
{{{ }}}
(三花括号)
record.
WHERE子句中的
{{{record.email}}}
输出过滤器
{{ }}
(双花括号)
record.
{{record.status}}
Delta URI参数
{{{ }}}
(三花括号)
(平台注入)
{{{lastExportDateTime}}}
可通过
@root
访问其他上下文对象:
对象描述
record
当前正在处理的记录
job
当前任务元数据
settings
集成/流程设置
connection
连接对象(用于认证头)
当配置一对多分组时,数据结构变为
batch_of_records
——需使用
{{#each batch_of_records}}
循环访问单个记录。

Key Syntax

核心语法

  • {{{triple-braces}}}
    -- raw output, no escaping. Use for URIs, SQL, JSON bodies, file paths -- anywhere commas, quotes, or ampersands matter. In RDBMS, triple braces output the raw value (
    value
    ); double braces wrap in single quotes (
    'value'
    ). Prefer triple and add literal quotes explicitly where needed.
  • {{double-braces}}
    -- context-dependent formatting. In RDBMS adds single quotes around the value. In URLs, URL-encodes. Use triple braces for explicit control.
  • Always use
    record.
    prefix (AFE 2.0)
    --
    {{{record.fieldName}}}
    in all contexts, never bare
    {{{fieldName}}}
    or
    {{{data.fieldName}}}
    (AFE 1.0). Nested fields:
    {{{record.properties.email}}}
    .
  • Exception: Mapper 1.0 (Salesforce/NetSuite) -- uses bare field names without
    record.
    prefix. This is the only context where bare field references are correct.
  • {{{triple-braces}}}
    ——原始输出,无转义。适用于URI、SQL、JSON请求体、文件路径等所有逗号、引号或&符号起作用的场景。在RDBMS中,三花括号输出原始值(
    value
    );双花括号会将值用单引号包裹(
    'value'
    )。优先使用三花括号,并在需要时显式添加字面引号。
  • {{double-braces}}
    ——依赖上下文的格式化。在RDBMS中会将值用单引号包裹;在URL中会进行URL编码。如需显式控制,请使用三花括号。
  • 在AFE 2.0中始终使用
    record.
    前缀
    ——所有上下文中均使用
    {{{record.fieldName}}}
    ,切勿使用裸
    {{{fieldName}}}
    {{{data.fieldName}}}
    (AFE 1.0)。嵌套字段:
    {{{record.properties.email}}}
  • 例外:Mapper 1.0(Salesforce/NetSuite)——使用不带
    record.
    前缀的裸字段名。这是唯一允许裸字段引用的上下文。

Related Skills

相关技能

  • configuring-exports > Quick Reference -- export adaptor types, delta sync setup, output filters
  • configuring-imports > Quick Reference -- import adaptor types, operation modes, mapping systems
  • writing-mappings > Quick Reference -- Mapper 2.0 fields, lookups, conditional mappings
<!-- TIER:2 -->
  • configuring-exports > Quick Reference——导出适配器类型、增量同步设置、输出过滤器
  • configuring-imports > Quick Reference——导入适配器类型、操作模式、映射系统
  • writing-mappings > Quick Reference——Mapper 2.0字段、查找、条件映射
<!-- TIER:2 -->

Syntax Fundamentals

语法基础

Braces

花括号

SyntaxBehaviorWhen to use
{{ }}
Context-dependent formatting -- RDBMS wraps value in single quotes (
'value'
), URLs get URL-encoded
Use only when auto-formatting is desired
{{{ }}}
Raw output, no escaping or wrappingPrefer everywhere -- SQL, JSON bodies, URIs, file paths. Add literal quotes yourself where needed
{{{{ }}}}
Raw block -- contents treated as literal stringEscaping Handlebars syntax itself
语法行为使用场景
{{ }}
依赖上下文的格式化——RDBMS将值用单引号包裹(
'value'
),URL进行URL编码
仅在需要自动格式化时使用
{{{ }}}
原始输出,无转义或包裹优先在所有场景使用——SQL、JSON请求体、URI、文件路径。在需要时自行添加字面引号
{{{{ }}}}
原始块——内容被视为字面字符串转义Handlebars语法本身

Field access

字段访问

PatternMeaning
record.fieldName
Standard field reference -- all contexts (AFE 2.0)
record.nested.field
Dot-notation for nested objects
record.[Field With Spaces]
Bracket notation for special characters in field names
record.items.[0].name
Array index access
@root.fieldName
Root context -- escape nested
#each
scope
../fieldName
Parent context -- one level up from current
#each
this
Current iteration element
@index
/
@key
Current array index / object key in
#each
@first
/
@last
Boolean -- first/last element in
#each
iteration
模式含义
record.fieldName
标准字段引用——所有AFE 2.0上下文
record.nested.field
嵌套对象的点标记法
record.[Field With Spaces]
含特殊字符字段名的方括号标记法
record.items.[0].name
数组索引访问
@root.fieldName
根上下文——跳出嵌套
#each
作用域
../fieldName
父上下文——当前
#each
的上一级
this
当前循环元素
@index
/
@key
#each
循环中的当前数组索引/对象键
@first
/
@last
布尔值——
#each
循环中的第一个/最后一个元素

Subexpressions (nesting helpers)

子表达式(嵌套辅助函数)

Use
()
to nest one helper's output as input to another. The inner helper evaluates first:
{{uppercase (split record.fullName " " 0)}}              -- split then uppercase the first word
{{{base64Encode (join ":" record.user record.pass)}}}    -- join then encode
{{#compare (add record.qty 1) ">" "100"}}...{{/compare}} -- add then compare
{{#each (after record.tags 3)}}...{{/each}}              -- slice then iterate
Subexpressions can be nested multiple levels deep. Each
()
resolves inside-out.
使用
()
将一个辅助函数的输出作为另一个辅助函数的输入。内部辅助函数先求值:
{{uppercase (split record.fullName " " 0)}}              -- 拆分后大写第一个单词
{{{base64Encode (join ":" record.user record.pass)}}}    -- 拼接后编码
{{#compare (add record.qty 1) ">" "100"}}...{{/compare}} -- 相加后比较
{{#each (after record.tags 3)}}...{{/each}}              -- 切片后循环
子表达式可多层嵌套。每个
()
从内到外解析。

Block helpers

块级辅助函数

  • {{#each record.items}}...{{/each}}
    -- iterate array or object
  • {{#if record.active}}...{{else}}...{{/if}}
    -- conditional
  • {{#compare val1 "==" val2}}...{{/compare}}
    -- comparison (
    ==
    ,
    ===
    ,
    !=
    ,
    !==
    ,
    <
    ,
    >
    ,
    <=
    ,
    >=
    )
  • {{#with record.address}}...{{/with}}
    -- change context scope
  • {{#each record.items}}...{{/each}}
    ——遍历数组或对象
  • {{#if record.active}}...{{else}}...{{/if}}
    ——条件判断
  • {{#compare val1 "==" val2}}...{{/compare}}
    ——比较(
    ==
    ===
    !=
    !==
    <
    >
    <=
    >=
  • {{#with record.address}}...{{/with}}
    ——更改上下文作用域

Date/time formatting

日期/时间格式化

Uses moment.js tokens. Always use triple braces for date output.
Common tokens:
YYYY
(4-digit year),
MM
(2-digit month),
DD
(2-digit day),
HH
(24h hour),
mm
(minute),
ss
(second),
SSS
(millisecond),
Z
(timezone offset),
X
(Unix seconds),
x
(Unix milliseconds).
Timezone: pass as third argument --
{{{dateFormat "YYYY-MM-DD" record.date "US/Eastern"}}}
.
使用moment.js标记。日期输出始终使用三花括号。
常用标记:
YYYY
(4位年份)、
MM
(2位月份)、
DD
(2位日期)、
HH
(24小时制小时)、
mm
(分钟)、
ss
(秒)、
SSS
(毫秒)、
Z
(时区偏移)、
X
(Unix秒数)、
x
(Unix毫秒数)。
时区:作为第三个参数传入——
{{{dateFormat "YYYY-MM-DD" record.date "US/Eastern"}}}

Date arithmetic

日期运算

dateAdd
works in milliseconds:
  • 1 hour = 3,600,000
  • 1 day = 86,400,000
  • 7 days = 604,800,000
dateAdd
毫秒为单位:
  • 1小时 = 3,600,000
  • 1天 = 86,400,000
  • 7天 = 604,800,000

Runtime Context at Each Stage

各阶段的运行时上下文

What
{{record.X}}
or
{{settings.Y}}
actually resolves to depends on which bubble the expression runs in. The shapes below were captured by setting
body: "{{{jsonSerialize this}}}"
on import/lookup bubbles and echoing through a mirror endpoint — they represent exactly what's available at runtime.
{{record.X}}
{{settings.Y}}
实际解析的值取决于表达式运行的作用域。以下结构是通过在导入/查找作用域中设置
body: "{{{jsonSerialize this}}}"
并通过镜像端点回显捕获的——它们准确代表了运行时的可用数据。

Import bubble (HTTPImport, NetSuiteDistributedImport, etc.)

导入作用域(HTTPImport、NetSuiteDistributedImport等)

Body templates and Handlebars in
mappings[].extract
run per-record with this context:
{
  "0": { ...the record at batch index 0, with mapped fields... },   // per-record
  "data": [ ...array of all records in this page, post-mapping... ],
  "lookup": { ...merged results from preceding lookup steps... },
  "recordLookupError": null | { ... },                               // set when a lookup failed
  "settings": { "import": {...}, "connection": {...} },
  "connection": { /* FULL connection object: auth, baseURI, etc. */ },
  "import": { /* full import config */ },
  "job": { "parentJob": { "_id", "type", "startedAt", ... } },
  "templateVersion": 1,
  "testMode": false
}
请求体模板和
mappings[].extract
中的Handlebars针对每条记录运行,上下文如下:
{
  "0": { ...批处理索引0的记录,含映射字段... },   // 单条记录
  "data": [ ...当前页中所有映射后的记录数组... ],
  "lookup": { ...之前查找步骤的合并结果... },
  "recordLookupError": null | { ... },                               // 查找失败时设置
  "settings": { "import": {...}, "connection": {...} },
  "connection": { /* 完整连接对象:认证、baseURI等 */ },
  "import": { /* 完整导入配置 */ },
  "job": { "parentJob": { "_id", "type", "startedAt", ... } },
  "templateVersion": 1,
  "testMode": false
}

Lookup bubble (HTTPExport with
isLookup: true
)

查找作用域(设置
isLookup: true
的HTTPExport)

Lookup request templates run per-record with a different shape:
{
  "exportStartTime": "ISO timestamp",
  "settings": { "export": {...}, "connection": {...} },
  "connection": { /* full connection object */ },

  // the record is spread at TOP LEVEL (not indexed by `0` like imports)
  "_id": "...",
  "name": "...",
  "<other record fields>": "...",

  "data": {
    /* copy of the record */,
    "_INITDATA": { /* original record before transforms */ }
  }
}
查找请求模板针对每条记录运行,结构不同
{
  "exportStartTime": "ISO时间戳",
  "settings": { "export": {...}, "connection": {...} },
  "connection": { /* 完整连接对象 */ },

  // 记录直接在顶层展开(不像导入中以`0`为索引)
  "_id": "...",
  "name": "...",
  "<其他记录字段>": "...",

  "data": {
    /* 记录副本 */,
    "_INITDATA": { /* 转换前的原始记录 */ }
  }
}

Export bubble (source generator)

导出作用域(源生成器)

Export URI templates and delta tokens have a minimal context — the platform injects
{{{lastExportDateTime}}}
,
{{{currentExportDateTime}}}
, plus
settings
and
connection
. No
record.
context exists yet (records haven't been fetched).
导出URI模板和Delta令牌的上下文极简——平台注入
{{{lastExportDateTime}}}
{{{currentExportDateTime}}}
,以及
settings
connection
。此时还没有
record.
上下文(记录尚未获取)。

Key differences between import and lookup contexts

导入与查找上下文的核心差异

Context keyImportLookup
Record location
0.<field>
+
data[].<field>
<field>
(top-level) +
data.<field>
data
shape
array of recordssingle record (with
_INITDATA
nested)
exportStartTime
NoYes
lookup
Yes (merged preceding results)N/A
import
/
job
/
recordLookupError
/
testMode
YesNo
connection
(full)
YesYes
上下文键导入查找
记录位置
0.<field>
+
data[].<field>
<field>
(顶层) +
data.<field>
data
结构
记录数组单条记录(嵌套
_INITDATA
exportStartTime
lookup
有(合并之前的结果)
import
/
job
/
recordLookupError
/
testMode
connection
(完整)

How to rediscover the shape for any bubble

如何重新发现任意作用域的结构

Set the body on an HTTP import or lookup to
{{{jsonSerialize this}}}
and point it at an echo endpoint (integrator.io's
/v1/mirror
works). Enable flow execution logging, run the flow, and inspect the
apiCall.response.body
— it's a copy of what you sent, which is the full runtime context. This works for any bubble whose adaptor sends an HTTP body.
将HTTP导入或查找的请求体设置为
{{{jsonSerialize this}}}
,并指向回显端点(integrator.io的
/v1/mirror
适用)。启用流程执行日志,运行流程,检查
apiCall.response.body
——这是你发送内容的副本,即完整的运行时上下文。此方法适用于任何发送HTTP请求体的适配器作用域。

How to Write a Handlebars Expression

如何编写Handlebars表达式

1. Identify the context

1. 确定上下文

Where the expression runs determines what data is available. In AFE 2.0, all contexts use
record.
to access the current record:
ContextAvailable dataPrefix
Mapping extractCurrent record
record.
HTTP body/URICurrent record
record.
RDBMS queryCurrent record
record.
Output filterCurrent record
record.
Delta URI parameterPlatform variables
lastExportDateTime
,
lastExportDateTimeUTC
Other context objects (
job
,
settings
,
connection
) are accessible via
@root
-- e.g.,
{{@root.connection.http.encrypted.apiKey}}
.
When one-to-many grouping is active, the shape is
batch_of_records
and you must iterate:
{{#each batch_of_records}}{{record.field}}{{/each}}
.
表达式的运行位置决定了可用的数据。在AFE 2.0中,所有上下文均使用
record.
访问当前记录:
上下文可用数据前缀
映射提取当前记录
record.
HTTP请求体/URI当前记录
record.
RDBMS查询当前记录
record.
输出过滤器当前记录
record.
Delta URI参数平台变量
lastExportDateTime
,
lastExportDateTimeUTC
其他上下文对象(
job
settings
connection
)可通过
@root
访问——例如
{{@root.connection.http.encrypted.apiKey}}
当一对多分组激活时,数据结构为
batch_of_records
,必须循环访问:
{{#each batch_of_records}}{{record.field}}{{/each}}

2. Know the data shape

2. 了解数据结构

Before writing any expression, inspect what the input data looks like:
bash
undefined
编写任何表达式前,先检查输入数据的结构:
bash
undefined

Test-run an export to see actual record shapes

测试运行导出查看实际记录结构

celigo exports invoke <exportId>
celigo exports invoke <exportId>

Check mock output for the expected shape

检查模拟输出以确认预期结构

celigo --jq '.mockOutput' exports get <exportId>
undefined
celigo --jq '.mockOutput' exports get <exportId>
undefined

3. Choose the right braces

3. 选择正确的花括号

  • Default to
    {{{ }}}
    (triple) for HTTP bodies, SQL, URIs, file paths
  • Use
    {{ }}
    (double) only in mapping extracts and display text where HTML escaping is acceptable
  • When in doubt, use triple -- raw output never breaks SQL or JSON; HTML-escaped output can
  • 默认对HTTP请求体、SQL、URI、文件路径使用
    {{{ }}}
    (三花括号)
  • 仅在映射提取和可接受HTML转义的显示文本中使用
    {{ }}
    (双花括号)
  • 如有疑问,使用三花括号——原始输出不会破坏SQL或JSON;HTML转义输出可能会

4. Find the right helper

4. 选择合适的辅助函数

See the helper index for all 79 custom helpers. Key categories:
  • Math --
    abs
    ,
    add
    ,
    subtract
    ,
    multiply
    ,
    divide
    ,
    modulo
    ,
    ceil
    ,
    floor
    ,
    round
    ,
    sum
    ,
    avg
    ,
    random
    ,
    toFixed
    ,
    toExponential
    ,
    toPrecision
  • String --
    uppercase
    ,
    lowercase
    ,
    capitalize
    ,
    capitalizeAll
    ,
    camelcase
    ,
    pascalcase
    ,
    snakecase
    ,
    dashcase
    ,
    dotcase
    ,
    pathcase
    ,
    sentence
    ,
    trim
    ,
    trimLeft
    ,
    trimRight
    ,
    padLeft
    ,
    padRight
    ,
    replace
    ,
    replacefirst
    ,
    removefirst
    ,
    chop
    ,
    truncateWords
    ,
    sanitize
    ,
    split
    ,
    join
    ,
    reverse
    ,
    occurrences
    ,
    substring
  • Array --
    after
    ,
    before
    ,
    first
    ,
    last
    ,
    reverse
    ,
    sort
    ,
    unique
    ,
    pluck
    ,
    arrayify
    ,
    lookup
    ,
    getValue
    ,
    sum
  • Date/time --
    dateFormat
    ,
    dateAdd
    ,
    timestamp
  • Encoding --
    base64Encode
    ,
    base64Decode
    ,
    htmlEncode
    ,
    htmlDecode
    ,
    jsonEncode
    ,
    jsonParse
    ,
    jsonSerialize
    ,
    encodeURI
    ,
    decodeURI
    ,
    stripProtocol
    ,
    stripQuerystring
  • Regex --
    regexMatch
    ,
    regexReplace
    ,
    regexSearch
  • Auth/crypto --
    hash
    ,
    hmac
    ,
    aws4
  • Type/logic --
    typeOf
    ,
    eq
    ,
    isTruthy
    ,
    isFalsey
    ,
    hasOwn
    ,
    hasNoItems
    ,
    compare
  • Format --
    addCommas
    ,
    bytes
    ,
    ordinalize
  • Block helpers --
    #each
    ,
    #if
    ,
    #compare
    ,
    #contains
    ,
    #filter
    ,
    #and
    ,
    #or
    ,
    #not
    ,
    #unless
    ,
    #with
    ,
    #some
    ,
    #startsWith
    ,
    #inArray
    ,
    #isEmpty
所有79个自定义辅助函数请参阅helper index。核心分类:
  • 数学运算——
    abs
    add
    subtract
    multiply
    divide
    modulo
    ceil
    floor
    round
    sum
    avg
    random
    toFixed
    toExponential
    toPrecision
  • 字符串处理——
    uppercase
    lowercase
    capitalize
    capitalizeAll
    camelcase
    pascalcase
    snakecase
    dashcase
    dotcase
    pathcase
    sentence
    trim
    trimLeft
    trimRight
    padLeft
    padRight
    replace
    replacefirst
    removefirst
    chop
    truncateWords
    sanitize
    split
    join
    reverse
    occurrences
    substring
  • 数组操作——
    after
    before
    first
    last
    reverse
    sort
    unique
    pluck
    arrayify
    lookup
    getValue
    sum
  • 日期/时间——
    dateFormat
    dateAdd
    timestamp
  • 编码——
    base64Encode
    base64Decode
    htmlEncode
    htmlDecode
    jsonEncode
    jsonParse
    jsonSerialize
    encodeURI
    decodeURI
    stripProtocol
    stripQuerystring
  • 正则表达式——
    regexMatch
    regexReplace
    regexSearch
  • 认证/加密——
    hash
    hmac
    aws4
  • 类型/逻辑——
    typeOf
    eq
    isTruthy
    isFalsey
    hasOwn
    hasNoItems
    compare
  • 格式化——
    addCommas
    bytes
    ordinalize
  • 块级辅助函数——
    #each
    #if
    #compare
    #contains
    #filter
    #and
    #or
    #not
    #unless
    #with
    #some
    #startsWith
    #inArray
    #isEmpty

5. Test the expression

5. 测试表达式

bash
undefined
bash
undefined

Invoke export to see if dynamic URI/query produces results

调用导出查看动态URI/查询是否生成结果

celigo exports invoke <exportId>
celigo exports invoke <exportId>

Invoke import to validate body template renders correctly

调用导入验证请求体模板渲染是否正确

celigo imports invoke <importId>
undefined
celigo imports invoke <importId>
undefined

Common Patterns

常见模式

JSON comma separation in HTTP body templates

HTTP请求体模板中的JSON逗号分隔

Avoid trailing commas when building JSON arrays:
{{#each record.items}}{...}{{#if @last}}{{else}},{{/if}}{{/each}}
构建JSON数组时避免尾随逗号:
{{#each record.items}}{...}{{#if @last}}{{else}},{{/if}}{{/each}}

Grouped data access (one-to-many / batch_of_records)

分组数据访问(一对多 / batch_of_records)

When one-to-many grouping is configured, the data shape becomes
batch_of_records
. Iterate to access individual records:
{{#each batch_of_records}}
  {{record.orderId}}
  {{record.[Shipping City]}}
{{/each}}
当配置一对多分组时,数据结构变为
batch_of_records
。需循环访问单个记录:
{{#each batch_of_records}}
  {{record.orderId}}
  {{record.[Shipping City]}}
{{/each}}

Conditional field with fallback

带回退的条件字段

{{#if record.nickname}}{{{record.nickname}}}{{else}}{{{record.firstName}}}{{/if}}
{{#if record.nickname}}{{{record.nickname}}}{{else}}{{{record.firstName}}}{{/if}}

Nested iteration with parent context

嵌套循环与父上下文

{{#each record.orders}}
  Order: {{{this.id}}}  Customer: {{{../customerName}}}
  {{#each this.items}}
    Item: {{{this.sku}}}
  {{/each}}
{{/each}}
{{#each record.orders}}
  订单:{{{this.id}}}  客户:{{{../customerName}}}
  {{#each this.items}}
    商品:{{{this.sku}}}
  {{/each}}
{{/each}}

SQL IN clause from list variable

基于列表变量的SQL IN子句

Build by a preSavePage hook (which can inject fields into the record), rendered with triple braces:
SELECT id FROM orders WHERE status IN ({{{record.statusList}}})
通过preSavePage钩子(可向记录中注入字段)构建,使用三花括号渲染:
SELECT id FROM orders WHERE status IN ({{{record.statusList}}})

JavaScript-to-Handlebars equivalents

JavaScript与Handlebars等效写法

JavaScriptHandlebars
str.split("?id=")[1]
{{split record.field "?id=" 1}}
str.replace("old", "new")
{{replace record.field "old" "new"}}
str.match(/pattern/)
{{{regexMatch record.field "pattern"}}}
Math.abs(n)
{{abs record.field}}
arr.length
{{record.items.length}}
<!-- TIER:3 -->
JavaScriptHandlebars
str.split("?id=")[1]
{{split record.field "?id=" 1}}
str.replace("old", "new")
{{replace record.field "old" "new"}}
str.match(/pattern/)
{{{regexMatch record.field "pattern"}}}
Math.abs(n)
{{abs record.field}}
arr.length
{{record.items.length}}
<!-- TIER:3 -->

Pre-Submit Checklist

提交前检查清单

Before finalizing any Handlebars expression, verify each item:
  • Prefer triple braces
    {{{ }}}
    .
    Double braces apply context-dependent formatting -- in RDBMS they wrap values in single quotes (
    'value'
    ), in URLs they URL-encode. Use triple braces for explicit control and add literal quotes where needed.
  • record.
    prefix everywhere (AFE 2.0).
    All contexts use
    record.fieldName
    -- mappings, HTTP bodies, SQL, filters. Never use bare
    fieldName
    ,
    data.fieldName
    , or
    data.0.fieldName
    (AFE 1.0). Exception: Mapper 1.0 (Salesforce/NetSuite) uses bare field names.
  • lastExportDateTime
    only in export context.
    This platform-injected variable is available in the export's HTTP/query context for delta syncs only -- not in mappings or import templates.
  • dateAdd
    values in milliseconds.
    1 day = 86,400,000. Not seconds, not hours.
  • #each
    context shifts.
    Inside
    {{#each}}
    ,
    this
    is the current item. Use
    ../
    for parent or
    @root
    for top-level fields.
  • Missing fields fail silently. Handlebars outputs empty string for undefined fields. Guard with
    {{#if field}}
    when the downstream system rejects empty values.
  • Bracket notation for special characters. Field names with spaces, dots, or hyphens need
    record.[Field Name]
    syntax.
  • compare
    is string-based.
    {{#compare "9" ">" "10"}}
    is TRUE (lexicographic). Convert values first or use strict operators.
  • Test with real data. Run
    celigo exports invoke
    or
    celigo imports invoke
    to verify the expression renders correctly with actual records.
在最终确定任何Handlebars表达式前,验证以下各项:
  • **优先使用三花括号
    {{{ }}}
    。**双花括号会应用依赖上下文的格式化——在RDBMS中会将值用单引号包裹(
    'value'
    ),在URL中会进行URL编码。使用三花括号进行显式控制,并在需要时添加字面引号。
  • **在AFE 2.0中所有场景使用
    record.
    前缀。**所有上下文(映射、HTTP请求体、SQL、过滤器)均使用
    record.fieldName
    。切勿使用裸
    fieldName
    data.fieldName
    data.0.fieldName
    (AFE 1.0)。例外:Mapper 1.0(Salesforce/NetSuite)使用裸字段名。
  • **
    lastExportDateTime
    仅在导出上下文使用。**此平台注入变量仅在导出的HTTP/查询上下文(用于增量同步)中可用——不适用于映射或导入模板。
  • **
    dateAdd
    的值以毫秒为单位。**1天 = 86,400,000。不是秒,也不是小时。
  • **
    #each
    会改变上下文。**在
    {{#each}}
    内部,
    this
    代表当前项。使用
    ../
    访问父上下文或
    @root
    访问顶层字段。
  • **缺失字段会静默失败。**Handlebars对未定义字段输出空字符串。当下游系统拒绝空值时,使用
    {{#if field}}
    进行防护。
  • **含特殊字符的字段使用方括号标记法。**字段名含空格、点或连字符时需使用
    record.[Field Name]
    语法。
  • compare
    基于字符串比较。
    {{#compare "9" ">" "10"}}
    结果为TRUE(字典序比较)。需先转换值或使用严格运算符。
  • **使用真实数据测试。**运行
    celigo exports invoke
    celigo imports invoke
    验证表达式在实际记录中的渲染结果。

Gotchas

常见陷阱

  1. Double braces apply auto-formatting.
    {{ }}
    adds context-dependent formatting -- in RDBMS it wraps values in single quotes (
    'value'
    ), in URLs it URL-encodes. This can corrupt SQL queries and JSON bodies. Prefer
    {{{ }}}
    (raw output) and add literal quotes explicitly where needed.
  2. Always use
    record.
    prefix (AFE 2.0).
    Use
    {{{record.fieldName}}}
    , not
    {{{fieldName}}}
    or
    {{{data.fieldName}}}
    . The
    record.
    prefix applies in all contexts -- mappings, HTTP, SQL, filters. Bare field names and
    data.
    prefix are deprecated AFE 1.0 syntax.
  3. lastExportDateTime
    is platform-injected.
    It exists only in the export's HTTP/query context for delta syncs -- not available in mappings or import templates.
  4. compare
    does string comparison.
    {{#compare "9" ">" "10"}}
    is TRUE because
    "9" > "1"
    lexicographically. Use the strict equality operators or convert values first.
  5. Nested
    #each
    changes context.
    Inside
    {{#each record.items}}
    ,
    this
    is the current item, not the record. Use
    ../
    to reach the parent or
    @root
    for the top-level context.
  6. dateAdd
    uses milliseconds, not seconds.
    Adding 1 day is
    86400000
    , not
    86400
    . A common mistake that produces dates seconds in the future instead of days.
  7. regexMatch
    returns the match string;
    regexSearch
    returns the position.
    Don't confuse them --
    regexSearch
    returns a number (0-indexed position), not the matched text.
  8. Raw blocks
    {{{{ }}}}
    output literal Handlebars syntax.
    They are for escaping
    {{ }}
    in output, not for "extra raw" rendering.
  9. Missing fields produce empty string silently. No error on missing fields -- Handlebars outputs nothing. Use
    {{#if field}}
    to guard when the downstream system rejects empty values.
  10. jsonEncode
    wraps a single value, not a whole body.
    It adds quotes and escapes special characters for embedding one field in a JSON string. Don't wrap the entire template in it.
  1. 双花括号会应用自动格式化。
    {{ }}
    会添加依赖上下文的格式化——在RDBMS中会将值用单引号包裹(
    'value'
    ),在URL中会进行URL编码。这可能破坏SQL查询和JSON请求体。优先使用
    {{{ }}}
    (原始输出),并在需要时显式添加字面引号。
  2. **在AFE 2.0中始终使用
    record.
    前缀。**使用
    {{{record.fieldName}}}
    ,而非
    {{{fieldName}}}
    {{{data.fieldName}}}
    record.
    前缀适用于所有上下文——映射、HTTP、SQL、过滤器。裸字段名和
    data.
    前缀是已弃用的AFE 1.0语法。
  3. **
    lastExportDateTime
    由平台注入。**它仅在导出的HTTP/查询上下文(用于增量同步)中存在——不适用于映射或导入模板。
  4. compare
    执行字符串比较。
    {{#compare "9" ">" "10"}}
    结果为TRUE,因为
    "9" > "1"
    (字典序)。需先转换为数值或重构逻辑。
  5. **嵌套
    #each
    会改变上下文。**在
    {{#each record.items}}
    内部,
    this
    代表当前项,而非记录。使用
    ../
    访问父上下文或
    @root
    访问顶层上下文。
  6. **
    dateAdd
    使用毫秒而非秒。**添加1天需使用
    86400000
    ,而非
    86400
    。这是一个常见错误,会导致日期仅提前几秒而非几天。
  7. **
    regexMatch
    返回匹配字符串;
    regexSearch
    返回位置。**请勿混淆——
    regexSearch
    返回数字(0索引位置),而非匹配文本。
  8. **原始块
    {{{{ }}}}
    输出字面Handlebars语法。**它们用于在输出中转义
    {{ }}
    ,而非“更原始”的渲染。
  9. **缺失字段会静默输出空字符串。**缺失字段不会报错——Handlebars输出空内容。当下游系统拒绝空值时,使用
    {{#if field}}
    进行防护。
  10. **
    jsonEncode
    包裹单个值,而非整个请求体。**它会添加引号并转义特殊字符,用于在JSON字符串中嵌入单个字段。请勿将整个模板用它包裹。

Common Errors

常见错误

SymptomCauseFix
&amp;
,
&lt;
, or unexpected
'quotes'
in SQL/JSON output
Double braces
{{ }}
applying auto-formatting (RDBMS adds single quotes, URLs get encoded)
Switch to triple braces
{{{ }}}
and add literal quotes where needed
Empty output, no errorMissing
record.
prefix (or using AFE 1.0
data.field
)
Change to
{{{record.fieldName}}}
-- applies in all contexts
Delta export returns all records
lastExportDateTime
used outside export context (e.g., in mapping)
Move to the export's
relativeURI
or query parameter
dateAdd
produces date seconds ahead instead of days
Value in seconds instead of millisecondsMultiply by 1000: use
86400000
not
86400
{{#compare "9" ">" "10"}}
is TRUE
String comparison, not numericConvert to number first or restructure logic
undefined
or empty in nested
#each
this
scope changed; referencing parent field without
../
Use
../fieldName
or
@root.fieldName
JSON body has trailing comma
{{#each}}
without comma-guard logic
Add
{{#if @last}}{{else}},{{/if}}
between items
Bracket notation field returns emptyUsing
record.Field Name
instead of
record.[Field Name]
Wrap field name in brackets:
record.[Field Name]
regexMatch
returns a number
Used
regexSearch
(returns position) instead of
regexMatch
Switch to
regexMatch
for the matched text
Entire body wrapped in quotesUsed
jsonEncode
on the whole template
Use
jsonEncode
only on individual field values, not the whole body
症状原因修复方案
SQL/JSON输出中出现
&amp;
&lt;
或意外的
'quotes'
双花括号
{{ }}
应用了自动格式化(RDBMS添加单引号,URL进行编码)
切换为三花括号
{{{ }}}
,并在需要时添加字面引号
输出为空,无错误缺失
record.
前缀(或使用AFE 1.0的
data.field
改为
{{{record.fieldName}}}
——适用于所有上下文
Delta导出返回所有记录
lastExportDateTime
在导出上下文外使用(如映射中)
移至导出的
relativeURI
或查询参数中
dateAdd
生成的日期仅提前几秒而非几天
值以秒为单位而非毫秒乘以1000:使用
86400000
而非
86400
{{#compare "9" ">" "10"}}
结果为TRUE
字符串比较而非数值比较先转换为数值或重构逻辑
嵌套
#each
中出现
undefined
或空值
this
作用域改变;未使用
../
引用父字段
使用
../fieldName
@root.fieldName
JSON请求体存在尾随逗号
{{#each}}
无逗号防护逻辑
在项之间添加
{{#if @last}}{{else}},{{/if}}
方括号标记法字段返回空值使用
record.Field Name
而非
record.[Field Name]
将字段名用方括号包裹:
record.[Field Name]
regexMatch
返回数字
使用了
regexSearch
(返回位置)而非
regexMatch
切换为
regexMatch
获取匹配文本
整个请求体被引号包裹对整个模板使用了
jsonEncode
仅对单个字段值使用
jsonEncode
,而非整个模板