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 -- prefix in all contexts (AFE 2.0),
record.for job/settings/connection, bracket notation for special characters@root - Helpers -- 79 custom helpers for math, string manipulation, dates, encoding, regex, and more
- Block helpers -- ,
#each,#if,#comparefor iteration and conditional logic#with - 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 fields, Handlebars concatenates, transforms, or conditionally selects values. The context is the current record.
mappings[].extract在导入的字段中,Handlebars用于拼接、转换或条件选择值。上下文为当前记录。
mappings[].extractHTTP request templates
HTTP请求模板
Export and import blocks use Handlebars in , , , and . Triple braces are essential to avoid HTML encoding of query parameters and JSON.
httprelativeURIbodyheaderspostBody导出和导入的块在、、和中使用Handlebars。三花括号对于避免查询参数和JSON的HTML转义至关重要。
httprelativeURIbodyheaderspostBodyRDBMS SQL queries
RDBMS SQL查询
SQL queries in use Handlebars with the mandatory 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.queryrecord.rdbms.queryrecord.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 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/查询上下文。
{{{lastExportDateTime}}}Quick Reference
快速参考
Context Decision Matrix (AFE 2.0)
上下文决策矩阵(AFE 2.0)
All contexts use prefix to access the current record's fields (AFE 2.0). Do NOT use bare field names, , or -- those are deprecated AFE 1.0 patterns. Exception: Mapper 1.0 (Salesforce/NetSuite) uses bare field names without prefix.
record.data.fielddata.0.fieldrecord.| Where | Syntax | Data prefix | Example |
|---|---|---|---|
| Mapping extract | | | |
| HTTP relative URI | | | |
| HTTP body / postBody | | | |
| SQL query (RDBMS) | | | |
| Output filter | | | |
| Delta URI parameter | | (platform-injected) | |
Additional context objects available via :
@root| Object | Description |
|---|---|
| Current record being processed |
| Current job metadata |
| Integration/flow settings |
| Connection object (for auth headers) |
When one-to-many grouping is configured, the data shape changes to -- iterate with to access individual records.
batch_of_records{{#each batch_of_records}}所有上下文均使用前缀访问当前记录的字段(AFE 2.0)。请勿使用裸字段名、或——这些是已弃用的AFE 1.0模式。**例外:**Mapper 1.0(Salesforce/NetSuite)使用不带前缀的裸字段名。
record.data.fielddata.0.fieldrecord.| 使用场景 | 语法 | 数据前缀 | 示例 |
|---|---|---|---|
| 映射提取 | | | |
| HTTP相对URI | | | URI中的 |
| HTTP请求体/postBody | | | JSON请求体中的 |
| SQL查询(RDBMS) | | | WHERE子句中的 |
| 输出过滤器 | | | |
| Delta URI参数 | | (平台注入) | |
可通过访问其他上下文对象:
@root| 对象 | 描述 |
|---|---|
| 当前正在处理的记录 |
| 当前任务元数据 |
| 集成/流程设置 |
| 连接对象(用于认证头) |
当配置一对多分组时,数据结构变为——需使用循环访问单个记录。
batch_of_records{{#each batch_of_records}}Key Syntax
核心语法
- -- 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 (
{{{triple-braces}}}); double braces wrap in single quotes (value). Prefer triple and add literal quotes explicitly where needed.'value' - -- context-dependent formatting. In RDBMS adds single quotes around the value. In URLs, URL-encodes. Use triple braces for explicit control.
{{double-braces}} - Always use prefix (AFE 2.0) --
record.in all contexts, never bare{{{record.fieldName}}}or{{{fieldName}}}(AFE 1.0). Nested fields:{{{data.fieldName}}}.{{{record.properties.email}}} - Exception: Mapper 1.0 (Salesforce/NetSuite) -- uses bare field names without prefix. This is the only context where bare field references are correct.
record.
- ——原始输出,无转义。适用于URI、SQL、JSON请求体、文件路径等所有逗号、引号或&符号起作用的场景。在RDBMS中,三花括号输出原始值(
{{{triple-braces}}});双花括号会将值用单引号包裹(value)。优先使用三花括号,并在需要时显式添加字面引号。'value' - ——依赖上下文的格式化。在RDBMS中会将值用单引号包裹;在URL中会进行URL编码。如需显式控制,请使用三花括号。
{{double-braces}} - 在AFE 2.0中始终使用前缀——所有上下文中均使用
record.,切勿使用裸{{{record.fieldName}}}或{{{fieldName}}}(AFE 1.0)。嵌套字段:{{{data.fieldName}}}。{{{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
- configuring-exports > Quick Reference——导出适配器类型、增量同步设置、输出过滤器
- configuring-imports > Quick Reference——导入适配器类型、操作模式、映射系统
- writing-mappings > Quick Reference——Mapper 2.0字段、查找、条件映射
Syntax Fundamentals
语法基础
Braces
花括号
| Syntax | Behavior | When to use |
|---|---|---|
| Context-dependent formatting -- RDBMS wraps value in single quotes ( | Use only when auto-formatting is desired |
| Raw output, no escaping or wrapping | Prefer everywhere -- SQL, JSON bodies, URIs, file paths. Add literal quotes yourself where needed |
| Raw block -- contents treated as literal string | Escaping Handlebars syntax itself |
| 语法 | 行为 | 使用场景 |
|---|---|---|
| 依赖上下文的格式化——RDBMS将值用单引号包裹( | 仅在需要自动格式化时使用 |
| 原始输出,无转义或包裹 | 优先在所有场景使用——SQL、JSON请求体、URI、文件路径。在需要时自行添加字面引号 |
| 原始块——内容被视为字面字符串 | 转义Handlebars语法本身 |
Field access
字段访问
| Pattern | Meaning |
|---|---|
| Standard field reference -- all contexts (AFE 2.0) |
| Dot-notation for nested objects |
| Bracket notation for special characters in field names |
| Array index access |
| Root context -- escape nested |
| Parent context -- one level up from current |
| Current iteration element |
| Current array index / object key in |
| Boolean -- first/last element in |
| 模式 | 含义 |
|---|---|
| 标准字段引用——所有AFE 2.0上下文 |
| 嵌套对象的点标记法 |
| 含特殊字符字段名的方括号标记法 |
| 数组索引访问 |
| 根上下文——跳出嵌套 |
| 父上下文——当前 |
| 当前循环元素 |
| |
| 布尔值—— |
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 iterateSubexpressions 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
块级辅助函数
- -- iterate array or object
{{#each record.items}}...{{/each}} - -- conditional
{{#if record.active}}...{{else}}...{{/if}} - -- comparison (
{{#compare val1 "==" val2}}...{{/compare}},==,===,!=,!==,<,>,<=)>= - -- change context scope
{{#with record.address}}...{{/with}}
- ——遍历数组或对象
{{#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: (4-digit year), (2-digit month), (2-digit day), (24h hour), (minute), (second), (millisecond), (timezone offset), (Unix seconds), (Unix milliseconds).
YYYYMMDDHHmmssSSSZXxTimezone: pass as third argument -- .
{{{dateFormat "YYYY-MM-DD" record.date "US/Eastern"}}}使用moment.js标记。日期输出始终使用三花括号。
常用标记:(4位年份)、(2位月份)、(2位日期)、(24小时制小时)、(分钟)、(秒)、(毫秒)、(时区偏移)、(Unix秒数)、(Unix毫秒数)。
YYYYMMDDHHmmssSSSZXx时区:作为第三个参数传入——。
{{{dateFormat "YYYY-MM-DD" record.date "US/Eastern"}}}Date arithmetic
日期运算
dateAdd- 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 or actually resolves to depends on which bubble the expression runs in. The shapes below were captured by setting 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}}}"{{record.X}}{{settings.Y}}body: "{{{jsonSerialize this}}}"Import bubble (HTTPImport, NetSuiteDistributedImport, etc.)
导入作用域(HTTPImport、NetSuiteDistributedImport等)
Body templates and Handlebars in run per-record with this context:
mappings[].extract{
"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
}请求体模板和中的Handlebars针对每条记录运行,上下文如下:
mappings[].extract{
"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查找作用域(设置isLookup: true
的HTTPExport)
isLookup: trueLookup 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 , , plus and . No context exists yet (records haven't been fetched).
{{{lastExportDateTime}}}{{{currentExportDateTime}}}settingsconnectionrecord.导出URI模板和Delta令牌的上下文极简——平台注入、,以及和。此时还没有上下文(记录尚未获取)。
{{{lastExportDateTime}}}{{{currentExportDateTime}}}settingsconnectionrecord.Key differences between import and lookup contexts
导入与查找上下文的核心差异
| Context key | Import | Lookup |
|---|---|---|
| Record location | | |
| array of records | single record (with |
| No | Yes |
| Yes (merged preceding results) | N/A |
| Yes | No |
| Yes | Yes |
| 上下文键 | 导入 | 查找 |
|---|---|---|
| 记录位置 | | |
| 记录数组 | 单条记录(嵌套 |
| 无 | 有 |
| 有(合并之前的结果) | 无 |
| 有 | 无 |
| 有 | 有 |
How to rediscover the shape for any bubble
如何重新发现任意作用域的结构
Set the body on an HTTP import or lookup to and point it at an echo endpoint (integrator.io's works). Enable flow execution logging, run the flow, and inspect the — 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.
{{{jsonSerialize this}}}/v1/mirrorapiCall.response.body将HTTP导入或查找的请求体设置为,并指向回显端点(integrator.io的适用)。启用流程执行日志,运行流程,检查——这是你发送内容的副本,即完整的运行时上下文。此方法适用于任何发送HTTP请求体的适配器作用域。
{{{jsonSerialize this}}}/v1/mirrorapiCall.response.bodyHow 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 to access the current record:
record.| Context | Available data | Prefix |
|---|---|---|
| Mapping extract | Current record | |
| HTTP body/URI | Current record | |
| RDBMS query | Current record | |
| Output filter | Current record | |
| Delta URI parameter | Platform variables | |
Other context objects (, , ) are accessible via -- e.g., .
jobsettingsconnection@root{{@root.connection.http.encrypted.apiKey}}When one-to-many grouping is active, the shape is and you must iterate: .
batch_of_records{{#each batch_of_records}}{{record.field}}{{/each}}表达式的运行位置决定了可用的数据。在AFE 2.0中,所有上下文均使用访问当前记录:
record.| 上下文 | 可用数据 | 前缀 |
|---|---|---|
| 映射提取 | 当前记录 | |
| HTTP请求体/URI | 当前记录 | |
| RDBMS查询 | 当前记录 | |
| 输出过滤器 | 当前记录 | |
| Delta URI参数 | 平台变量 | |
其他上下文对象(、、)可通过访问——例如。
jobsettingsconnection@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
undefinedTest-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>
undefinedceligo --jq '.mockOutput' exports get <exportId>
undefined3. 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,toExponentialtoPrecision - 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,occurrencessubstring - Array -- ,
after,before,first,last,reverse,sort,unique,pluck,arrayify,lookup,getValuesum - Date/time -- ,
dateFormat,dateAddtimestamp - Encoding -- ,
base64Encode,base64Decode,htmlEncode,htmlDecode,jsonEncode,jsonParse,jsonSerialize,encodeURI,decodeURI,stripProtocolstripQuerystring - Regex -- ,
regexMatch,regexReplaceregexSearch - Auth/crypto -- ,
hash,hmacaws4 - Type/logic -- ,
typeOf,eq,isTruthy,isFalsey,hasOwn,hasNoItemscompare - Format -- ,
addCommas,bytesordinalize - 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、toExponentialtoPrecision - 字符串处理——、
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、occurrencessubstring - 数组操作——、
after、before、first、last、reverse、sort、unique、pluck、arrayify、lookup、getValuesum - 日期/时间——、
dateFormat、dateAddtimestamp - 编码——、
base64Encode、base64Decode、htmlEncode、htmlDecode、jsonEncode、jsonParse、jsonSerialize、encodeURI、decodeURI、stripProtocolstripQuerystring - 正则表达式——、
regexMatch、regexReplaceregexSearch - 认证/加密——、
hash、hmacaws4 - 类型/逻辑——、
typeOf、eq、isTruthy、isFalsey、hasOwn、hasNoItemscompare - 格式化——、
addCommas、bytesordinalize - 块级辅助函数——、
#each、#if、#compare、#contains、#filter、#and、#or、#not、#unless、#with、#some、#startsWith、#inArray#isEmpty
5. Test the expression
5. 测试表达式
bash
undefinedbash
undefinedInvoke 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>
undefinedceligo imports invoke <importId>
undefinedCommon 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 . Iterate to access individual records:
batch_of_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等效写法
| JavaScript | Handlebars |
|---|---|
| |
| |
| |
| |
| |
| JavaScript | Handlebars |
|---|---|
| |
| |
| |
| |
| |
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 (
{{{ }}}), in URLs they URL-encode. Use triple braces for explicit control and add literal quotes where needed.'value' - prefix everywhere (AFE 2.0). All contexts use
record.-- mappings, HTTP bodies, SQL, filters. Never use barerecord.fieldName,fieldName, ordata.fieldName(AFE 1.0). Exception: Mapper 1.0 (Salesforce/NetSuite) uses bare field names.data.0.fieldName - 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.
lastExportDateTime - values in milliseconds. 1 day = 86,400,000. Not seconds, not hours.
dateAdd - context shifts. Inside
#each,{{#each}}is the current item. Usethisfor parent or../for top-level fields.@root - Missing fields fail silently. Handlebars outputs empty string for undefined fields. Guard with when the downstream system rejects empty values.
{{#if field}} - Bracket notation for special characters. Field names with spaces, dots, or hyphens need syntax.
record.[Field Name] - is string-based.
compareis TRUE (lexicographic). Convert values first or use strict operators.{{#compare "9" ">" "10"}} - Test with real data. Run or
celigo exports invoketo verify the expression renders correctly with actual records.celigo imports invoke
在最终确定任何Handlebars表达式前,验证以下各项:
- **优先使用三花括号。**双花括号会应用依赖上下文的格式化——在RDBMS中会将值用单引号包裹(
{{{ }}}),在URL中会进行URL编码。使用三花括号进行显式控制,并在需要时添加字面引号。'value' - **在AFE 2.0中所有场景使用前缀。**所有上下文(映射、HTTP请求体、SQL、过滤器)均使用
record.。切勿使用裸record.fieldName、fieldName或data.fieldName(AFE 1.0)。例外:Mapper 1.0(Salesforce/NetSuite)使用裸字段名。data.0.fieldName - **仅在导出上下文使用。**此平台注入变量仅在导出的HTTP/查询上下文(用于增量同步)中可用——不适用于映射或导入模板。
lastExportDateTime - **的值以毫秒为单位。**1天 = 86,400,000。不是秒,也不是小时。
dateAdd - **会改变上下文。**在
#each内部,{{#each}}代表当前项。使用this访问父上下文或../访问顶层字段。@root - **缺失字段会静默失败。**Handlebars对未定义字段输出空字符串。当下游系统拒绝空值时,使用进行防护。
{{#if field}} - **含特殊字符的字段使用方括号标记法。**字段名含空格、点或连字符时需使用语法。
record.[Field Name] - 基于字符串比较。
compare结果为TRUE(字典序比较)。需先转换值或使用严格运算符。{{#compare "9" ">" "10"}} - **使用真实数据测试。**运行或
celigo exports invoke验证表达式在实际记录中的渲染结果。celigo imports invoke
Gotchas
常见陷阱
- Double braces apply auto-formatting. adds context-dependent formatting -- in RDBMS it wraps values in single quotes (
{{ }}), in URLs it URL-encodes. This can corrupt SQL queries and JSON bodies. Prefer'value'(raw output) and add literal quotes explicitly where needed.{{{ }}} - Always use prefix (AFE 2.0). Use
record., not{{{record.fieldName}}}or{{{fieldName}}}. The{{{data.fieldName}}}prefix applies in all contexts -- mappings, HTTP, SQL, filters. Bare field names andrecord.prefix are deprecated AFE 1.0 syntax.data. - is platform-injected. It exists only in the export's HTTP/query context for delta syncs -- not available in mappings or import templates.
lastExportDateTime - does string comparison.
compareis TRUE because{{#compare "9" ">" "10"}}lexicographically. Use the strict equality operators or convert values first."9" > "1" - Nested changes context. Inside
#each,{{#each record.items}}is the current item, not the record. Usethisto reach the parent or../for the top-level context.@root - uses milliseconds, not seconds. Adding 1 day is
dateAdd, not86400000. A common mistake that produces dates seconds in the future instead of days.86400 - returns the match string;
regexMatchreturns the position. Don't confuse them --regexSearchreturns a number (0-indexed position), not the matched text.regexSearch - Raw blocks output literal Handlebars syntax. They are for escaping
{{{{ }}}}in output, not for "extra raw" rendering.{{ }} - Missing fields produce empty string silently. No error on missing fields -- Handlebars outputs nothing. Use to guard when the downstream system rejects empty values.
{{#if field}} - 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.
jsonEncode
- 双花括号会应用自动格式化。会添加依赖上下文的格式化——在RDBMS中会将值用单引号包裹(
{{ }}),在URL中会进行URL编码。这可能破坏SQL查询和JSON请求体。优先使用'value'(原始输出),并在需要时显式添加字面引号。{{{ }}} - **在AFE 2.0中始终使用前缀。**使用
record.,而非{{{record.fieldName}}}或{{{fieldName}}}。{{{data.fieldName}}}前缀适用于所有上下文——映射、HTTP、SQL、过滤器。裸字段名和record.前缀是已弃用的AFE 1.0语法。data. - **由平台注入。**它仅在导出的HTTP/查询上下文(用于增量同步)中存在——不适用于映射或导入模板。
lastExportDateTime - 执行字符串比较。
compare结果为TRUE,因为{{#compare "9" ">" "10"}}(字典序)。需先转换为数值或重构逻辑。"9" > "1" - **嵌套会改变上下文。**在
#each内部,{{#each record.items}}代表当前项,而非记录。使用this访问父上下文或../访问顶层上下文。@root - **使用毫秒而非秒。**添加1天需使用
dateAdd,而非86400000。这是一个常见错误,会导致日期仅提前几秒而非几天。86400 - **返回匹配字符串;
regexMatch返回位置。**请勿混淆——regexSearch返回数字(0索引位置),而非匹配文本。regexSearch - **原始块输出字面Handlebars语法。**它们用于在输出中转义
{{{{ }}}},而非“更原始”的渲染。{{ }} - **缺失字段会静默输出空字符串。**缺失字段不会报错——Handlebars输出空内容。当下游系统拒绝空值时,使用进行防护。
{{#if field}} - **包裹单个值,而非整个请求体。**它会添加引号并转义特殊字符,用于在JSON字符串中嵌入单个字段。请勿将整个模板用它包裹。
jsonEncode
Common Errors
常见错误
| Symptom | Cause | Fix |
|---|---|---|
| Double braces | Switch to triple braces |
| Empty output, no error | Missing | Change to |
| Delta export returns all records | | Move to the export's |
| Value in seconds instead of milliseconds | Multiply by 1000: use |
| String comparison, not numeric | Convert to number first or restructure logic |
| | Use |
| JSON body has trailing comma | | Add |
| Bracket notation field returns empty | Using | Wrap field name in brackets: |
| Used | Switch to |
| Entire body wrapped in quotes | Used | Use |
| 症状 | 原因 | 修复方案 |
|---|---|---|
SQL/JSON输出中出现 | 双花括号 | 切换为三花括号 |
| 输出为空,无错误 | 缺失 | 改为 |
| Delta导出返回所有记录 | | 移至导出的 |
| 值以秒为单位而非毫秒 | 乘以1000:使用 |
| 字符串比较而非数值比较 | 先转换为数值或重构逻辑 |
嵌套 | | 使用 |
| JSON请求体存在尾随逗号 | | 在项之间添加 |
| 方括号标记法字段返回空值 | 使用 | 将字段名用方括号包裹: |
| 使用了 | 切换为 |
| 整个请求体被引号包裹 | 对整个模板使用了 | 仅对单个字段值使用 |