对上下文数据进行迭代 personalization-contexts

在此页面上:​了解如何使用Handlebars迭代语法从上下文数据源(如事件、自定义操作响应和数据集查找)循环数组以在消息中显示动态列表。

了解如何使用Handlebars迭代语法在消息中显示来自各种源的数据的动态列表,包括事件、自定义操作响应和其他上下文数据。

概述 overview

消息个性化期间,Journey Optimizer允许从多个来源访问上下文数据。 您可以使用本机渠道(电子邮件推送短信)中的Handlebars语法对这些源中的数组进行迭代,以显示动态内容,如产品列表、推荐或其他重复元素。

可用的上下文源:

本指南向您展示了如何在消息中从每个来源对阵列进行迭代,以及在配置历程活动时如何使用阵列。 从Handlebars迭代语法开始,了解消息个性化基本知识,或跳转到使用历程表达式中的数组,了解如何将数组数据传递给自定义操作和数据集查找。

Handlebars迭代语法 syntax

Handlebars提供{{#each}} 帮助程序以通过数组进行迭代。 基本语法为:

{{#each arrayPath as |item|}}
  <!-- Access item properties here -->
  {{item.property}}
{{/each}}

关键点:

  • arrayPath替换为数组数据的路径
  • item替换为您喜欢的任何变量名称(例如,productresponseelement
  • 使用{{item.propertyName}}访问每个项目的属性
  • 您可以为多级数组嵌套多个{{#each}}

对事件数据进行迭代 event-data

当您的历程由事件触发时,事件数据可用。 这有助于显示历程开始时捕获的数据,例如购物车内容、订单项目或表单提交。

TIP
您可以将事件数据与其他源相结合。 有关示例,请参阅合并多个上下文源

事件的上下文路径

context.journey.events.<event_ID>.<fieldPath>
  • <event_ID>:历程中配置的事件唯一ID
  • <fieldPath>:事件架构中字段或数组的路径
NOTE
数值事件ID需要反撇号。 如果事件ID是数字(例如,1697323153),请在表达式路径中以反撇号(`)将其换行。 如果没有反撇号,PQL解析器会引发语法错误。
code language-handlebars
context.journey.events.`1697323153`.fieldName
有关更多详细信息和完整的示例,包括来自事件时间戳的日期格式,请参阅来自上下文事件的时间戳格式

示例:事件中的购物车项目

如果您的事件架构包含productListItems数组(标准XDM格式),您可以显示购物车内容,如下面的示例中详述。

查看示例代码
code language-handlebars
{{#each context.journey.events.event_ID.productListItems as |product|}}
  <div class="product">
    <h3>{{product.name}}</h3>
    <p>Quantity: {{product.quantity}}</p>
    <p>Price: ${{product.priceTotal}}</p>
  </div>
{{/each}}

示例:事件中的嵌套数组

对于嵌套结构,使用嵌套的{{#each}}块。

查看示例代码
code language-handlebars
{{#each context.journey.events.event_ID.categories as |category|}}
  <h2>{{category.name}}</h2>
  <ul>
    {{#each category.items as |item|}}
      <li>{{item.title}}</li>
    {{/each}}
  </ul>
{{/each}}

最佳实践中了解有关嵌套的更多信息。

迭代自定义操作响应 custom-action-responses

自定义操作响应包含从外部API调用返回的数据。 这对于显示系统中的实时信息非常有用,例如忠诚度点数、产品推荐、库存状态或个性化优惠。

NOTE
必须为自定义操作配置响应有效负载才能使用此功能。 有关详细信息,请参阅此部分。 您还可以将自定义操作响应与事件数据或数据集查找相结合 — 请参阅合并多个上下文源以获取示例。

自定义操作的上下文路径

context.journey.actions.<actionName>.<fieldPath>
  • <actionName>:历程中配置的自定义操作的名称
  • <fieldPath>:响应有效负载中字段或数组的路径

示例:来自API的产品推荐

要迭代从自定义操作返回的一系列产品推荐,并在消息中将它们显示为单个卡片,请参阅以下示例。

查看示例代码

API响应:

code language-json
{
  "recommendations": [
    {
      "productId": "12345",
      "productName": "Summer Jacket",
      "price": 89.99,
      "imageUrl": "https://example.com/jacket.jpg"
    },
    {
      "productId": "67890",
      "productName": "Running Shoes",
      "price": 129.99,
      "imageUrl": "https://example.com/shoes.jpg"
    }
  ]
}

消息个性化:

code language-handlebars
<h2>Recommended for You</h2>
<div class="recommendations">
  {{#each context.journey.actions.GetRecommendations.recommendations as |item|}}
    <div class="product-card">
      <img src="{{item.imageUrl}}" alt="{{item.productName}}" />
      <h3>{{item.productName}}</h3>
      <p class="price">${{item.price}}</p>
    </div>
  {{/each}}
</div>

示例:自定义操作中的嵌套数组

要迭代包含嵌套数组(一个对象数组,其中每个对象都包含另一个数组)的自定义操作响应,请参阅以下示例。 此演示使用嵌套的{{#each}}循环访问多个级别的数据。

查看示例代码

API响应:

code language-json
{
  "id": "84632848268632",
  "responses": [
    { "productIDs": [1111, 2222, 3333] },
    { "productIDs": [4444, 5555, 6666] },
    { "productIDs": [7777, 8888, 9999] }
  ]
}

消息个性化:

code language-handlebars
<h2>Product Groups</h2>
{{#each context.journey.actions.GetProducts.responses as |response|}}
  <div class="product-group">
    <ul>
      {{#each response.productIDs as |productID|}}
        <li>Product ID: {{productID}}</li>
      {{/each}}
    </ul>
  </div>
{{/each}}

有关更复杂的嵌套模式,请参阅最佳实践

示例:忠诚度层级优势

要根据忠诚度状态显示动态福利,请参阅以下示例。

查看示例代码

API响应:

code language-json
{
  "loyaltyTier": "gold",
  "benefits": [
    { "name": "Free shipping", "icon": "truck" },
    { "name": "20% discount", "icon": "percent" },
    { "name": "Priority support", "icon": "headset" }
  ]
}

消息个性化:

code language-handlebars
<h2>Your {{context.journey.actions.GetLoyaltyInfo.loyaltyTier}} Member Benefits</h2>
<ul class="benefits">
  {{#each context.journey.actions.GetLoyaltyInfo.benefits as |benefit|}}
    <li>
      <span class="icon-{{benefit.icon}}"></span>
      {{benefit.name}}
    </li>
  {{/each}}
</ul>

对数据集查找结果进行迭代 dataset-lookup

数据集查找活动允许您在历程运行时从Adobe Experience Platform数据集中检索数据。 扩充的数据将作为数组存储,并可在消息中迭代。

此部分中了解有关配置数据集查找活动的更多信息。 与事件数据结合使用时,数据集查找功能尤为强大 — 请参阅示例:通过数据集查找扩充了事件数据以了解实际用例。

数据集查找的上下文路径

context.journey.datasetLookup.<activityID>.entities
  • <activityID>:数据集查找活动的唯一ID
  • entities:从数据集中检索的扩充数据数组

示例:数据集中的产品详细信息

如果您使用数据集查找活动根据SKU检索产品信息,请参阅以下示例。

查看示例代码

数据集查找配置:

  • 查找键: list(@event{purchase_event.products.sku})
  • 要返回的字段: ["SKU", "category", "price", "name"]

消息个性化:

code language-handlebars
<h2>Product Details</h2>
<table>
  <thead>
    <tr>
      <th>Product Name</th>
      <th>Category</th>
      <th>Price</th>
    </tr>
  </thead>
  <tbody>
    {{#each context.journey.datasetLookup.3709000.entities as |product|}}
      <tr>
        <td>{{product.name}}</td>
        <td>{{product.category}}</td>
        <td>${{product.price}}</td>
      </tr>
    {{/each}}
  </tbody>
</table>

示例:使用数据集数据过滤的迭代

要在迭代期间筛选数据集查找结果并仅显示符合特定条件的项(例如,特定类别中的产品),请在{{#each}}循环中使用条件{{#if}}语句。 请参阅以下示例。

查看示例代码
code language-handlebars
<h2>Household Products</h2>
{{#each context.journey.datasetLookup.3709000.entities as |product|}}
  {{#if product.category = "household"}}
    <div class="product">
      <h3>{{product.name}}</h3>
      <p>Price: ${{product.price}}</p>
    </div>
  {{/if}}
{{/each}}

最佳实践中了解有关条件筛选的更多信息。

示例:通过数据集查找计算总数

要在迭代数据集查找结果时计算并显示总计,请参阅以下示例。

查看示例代码
code language-handlebars
{% let householdTotal = 0 %}
{{#each context.journey.datasetLookup.3709000.entities as |product|}}
  {%#if product.category = "household"%}
    {% let householdTotal = householdTotal + product.price %}
  {%/if%}
{{/each}}

<p>Your household products total: ${{householdTotal}}</p>

使用历程技术属性 technical-properties

历程技术属性提供对旅程执行相关元数据的访问权限,例如旅程ID和补充标识符。 在与迭代模式结合使用时,这些规则可能很有用,尤其是对于根据特定历程实例筛选数组。

可用的技术属性

context.journey.technicalProperties.journeyUID
context.journey.technicalProperties.supplementalId

示例:使用补充标识符筛选数组项

在具有数组的事件触发的历程中使用补充标识符时,您可以进行筛选以仅显示当前历程实例的相关项目。 在本指南中了解有关补充标识符的更多信息。

场景:历程通过多个预订触发,但您只想显示触发此历程实例的特定预订(由补充ID标识)的信息。

查看示例代码
code language-handlebars
{{#each context.journey.events.event_ID.bookingList as |booking|}}
  {%#if booking.bookingInfo.bookingNum = context.journey.technicalProperties.supplementalId%}
    <div class="booking-details">
      <h3>Your Booking: {{booking.bookingInfo.bookingNum}}</h3>
      <p>Destination: {{booking.bookingInfo.bookingCountry}}</p>
      <p>Date: {{booking.bookingInfo.bookingDate}}</p>
    </div>
  {%/if%}
{{/each}}

示例:包含用于跟踪的历程ID

要在消息中包含历程ID以进行跟踪,请参阅以下示例。

查看示例代码
code language-handlebars
<footer>
  <p>Journey Reference: {{context.journey.technicalProperties.journeyUID}}</p>
</footer>

合并多个上下文源 combine-sources

您可以将来自不同来源的数据合并到同一消息中,以创建丰富且个性化的体验。 本节显示了将多个上下文源结合使用的实际示例。

可以合并的上下文源:

示例:具有实时库存的购物车项目

要将事件数据(购物车内容)与自定义操作数据(库存状态)相结合,请查看以下示例。

查看示例代码
code language-handlebars
<h2>Your Cart</h2>
{{#each context.journey.events.cartEvent.productListItems as |product|}}
  <div class="cart-item">
    <h3>{{product.name}}</h3>
    <p>Quantity: {{product.quantity}}</p>
    <p>Price: ${{product.priceTotal}}</p>
  </div>
{{/each}}

<h2>We Also Recommend</h2>
{{#each context.journey.actions.GetRecommendations.items as |recommendation|}}
  <div class="recommendation">
    <h4>{{recommendation.name}}</h4>
    <p>${{recommendation.price}}</p>
    {{#if recommendation.inStock}}
      <span class="badge">In Stock</span>
    {{else}}
      <span class="badge out-of-stock">Out of Stock</span>
    {{/if}}
  </div>
{{/each}}

示例:通过数据集查找扩充了事件数据

要将事件SKU数据集查找中的详细产品信息相结合,请查看以下示例。

查看示例代码
code language-handlebars
<h2>Your Order Details</h2>
{{#each context.journey.events.orderEvent.productListItems as |item|}}
  <div class="order-item">
    <p><strong>SKU:</strong> {{item.SKU}}</p>
    <p><strong>Quantity:</strong> {{item.quantity}}</p>

    <!-- Enrich with dataset lookup data -->
    {{#each context.journey.datasetLookup.1234567.entities as |enrichedProduct|}}
      {{#if enrichedProduct.SKU = item.SKU}}
        <p><strong>Product Name:</strong> {{enrichedProduct.name}}</p>
        <p><strong>Category:</strong> {{enrichedProduct.category}}</p>
        <img src="{{enrichedProduct.imageUrl}}" alt="{{enrichedProduct.name}}" />
      {{/if}}
    {{/each}}
  </div>
{{/each}}

示例:将多个源与技术属性相结合

要将多个上下文源(用户档案数据、事件数据、自定义操作和技术属性)合并到一封邮件中,请查看以下示例。

查看示例代码
code language-handlebars
<div class="personalized-content">
  <!-- Profile data -->
  <h1>Hello {{profile.person.name.firstName}},</h1>

  <!-- Event data iteration -->
  <h2>Your Recent Purchases</h2>
  {{#each context.journey.events.purchaseEvent.items as |purchase|}}
    <div class="purchase">
      <p>{{purchase.productName}} - ${{purchase.price}}</p>
    </div>
  {{/each}}

  <!-- Custom action response iteration -->
  <h2>Recommended for You</h2>
  {{#each context.journey.actions.GetPersonalizedRecs.recommendations as |rec|}}
    <div class="recommendation">
      <h3>{{rec.title}}</h3>
      <p>{{rec.description}}</p>
    </div>
  {{/each}}

  <!-- Technical properties -->
  <footer>
    <p class="fine-print">Journey ID: {{context.journey.technicalProperties.journeyUID}}</p>
  </footer>
</div>

其他上下文类型 other-contexts

虽然本指南侧重于数组上的迭代,但其他上下文类型可用于个性化,通常不需要迭代。 这些组件直接访问,而不是循环访问:

  • 配置文件属性 (profile.*): Adobe Experience Platform中的各个配置文件字段
  • 受众 (inAudience()):受众成员资格检查
  • 优惠决策:决策管理优惠
  • 目标属性(仅限编排的营销活动):在营销活动画布上计算的属性,包括扩充收藏集数组
  • 令牌 (context.token):会话或身份验证令牌

有关使用这些源的完整个性化语法和示例,请参阅:

在历程表达式中使用数组 arrays-in-journeys

虽然上一节侧重于使用Handlebars在消息个性化中迭代使用数组,但在配置历程活动时也可以使用数组。 本节介绍如何在历程表达式中使用来自事件的数组数据,尤其是将数据传递给自定义操作或使用具有数据集查找的数组时。

IMPORTANT
历程表达式使用与Handlebars个性化不同的语法。 在历程配置(如自定义操作参数或条件)中,您将历程表达式编辑器与诸如firstallserializeList之类的函数一起使用。 在消息内容中,您将Handlebars语法与{{#each}}循环一起使用。

将数组值传递到自定义操作参数 arrays-to-custom-actions

在配置自定义操作时,您通常需要从事件数组中提取值,并将其作为参数传递。 本节介绍常见模式。

了解有关在中将集合传递到自定义操作参数中的详细信息。

从数组中提取单个值

用例:从事件数组中获取特定字段,以作为查询参数传递到GET请求中。

查看示例代码

示例场景:从产品列表中提取价格大于0的第一个SKU。

事件架构示例

code language-json
{
  "commerce": {
    "productListItems": [
      { "SKU": "SKU-1", "priceTotal": 10.0 },
      { "SKU": "SKU-2", "priceTotal": 0.0 },
      { "SKU": "SKU-3", "priceTotal": 20.0 }
    ]
  }
}

自定义操作配置

  1. 在自定义操作中,使用类型string配置查询参数(例如sku
  2. 将其标记为Variable以允许动态值

操作参数​ 中的 ​表达式历程:

code language-javascript
@event{YourEventName.commerce.productListItems.first(currentEventField.priceTotal > 0).SKU}

说明

  • @event{YourEventName}:引用您的历程事件
  • .first(currentEventField.condition):返回与条件匹配的第一个数组项
  • currentEventField:代表事件数组中的每个项,因为您循环遍历它
  • .SKU:从匹配项提取SKU字段
  • 结果: "SKU-1" (适用于操作参数的字符串)

了解有关集合管理函数中的first函数的更多信息。

从数组构建值列表

用例:创建以逗号分隔的ID列表以作为查询参数传递(例如,/products?ids=sku1,sku2,sku3)。

查看示例代码

自定义操作配置

  1. 使用类型string配置查询参数(例如ids
  2. 将其标记为Variable

历程表达式

code language-javascript
serializeList(
  @event{YourEventName.commerce.productListItems.all(currentEventField.priceTotal > 0).SKU},
  ",",
  true
)

说明

  • .all(currentEventField.condition):返回与条件匹配的所有数组项(返回列表)

  • currentEventField:代表事件数组中的每个项,因为您循环遍历它

  • .SKU:对列表进行项目以仅包含SKU值

  • serializeList(list, delimiter, addQuotes):将列表加入字符串

    • ",":使用逗号作为分隔符
    • true:在每个字符串元素周围添加引号
  • 结果: "SKU-1,SKU-3" (适用于查询参数)

详细了解:

将集合传递到自定义操作参数中涵盖了自定义操作的集合处理。

将对象数组传递给自定义操作

用例:发送请求正文中的对象的完整数组(对于POST或包含正文的GET)。

查看示例代码

请求正文示例

code language-json
{
  "ctxt": {
    "products": [
      {
        "id": "productA",
        "name": "Product A",
        "price": 20.1,
        "color": "blue"
      }
    ]
  }
}

自定义操作配置

  1. 在请求正文中,将products定义为类型listObject
  2. 将其标记为Variable
  3. 定义对象字段: idnamepricecolor(每个字段都变为可映射)

历程画布配置

  1. 在高级模式下,设置集合表达式:

    code language-javascript
    @event{YourEventName.commerce.productListItems.all(currentEventField.priceTotal > 0)}
    
  2. 在收藏集映射UI中:

    • id映射→productListItems.SKU
    • name映射→productListItems.name
    • price映射→productListItems.priceTotal
    • color映射→productListItems.color

Journey Optimizer会构建与操作有效负载结构匹配的对象数组。

note
NOTE
使用事件数组时,使用currentEventField引用每个项。 对于数据源集合(Adobe Experience Platform),请使用currentDataPackField。 对于自定义操作响应集合,请使用currentActionField

请参阅将集合传递到自定义操作参数以了解详情。

使用数组进行数据集查找 arrays-with-dataset-lookup

使用数据集查找活动时,您可以将一组值作为查找键传递以检索扩充数据。

示例:查找事件数组中所有SKU的产品详细信息。

查看示例代码

数据集查找配置

在查找键字段中,使用list()将数组路径转换为列表:

code language-javascript
list(@event{purchaseEvent.productListItems.SKU})

这将创建一个列表,其中包含要在数据集中查找的所有SKU值。 结果在context.journey.datasetLookup.<activityID>.entities处可用作数组,您可以在消息中对其进行迭代(请参阅对数据集查找结果进行迭代)。

限制和模式 array-limitations

在历程中使用数组时,请注意以下限制:

在历程流中无需对阵列进行动态循环

历程无法创建动态循环,其中数组中的每个项会多次执行一个操作节点。 这是为了防止出现性能失控问题。

您无法执行的操作

  • 为每个数组项动态执行一次自定义操作
  • 根据数组长度创建多个历程分支

推荐的模式

  1. 一次发送所有项:将整个数组或序列化列表传递到单个处理所有项的自定义操作。 请参阅从数组生成值列表。

  2. 使用外部聚合:让外部API接受多个ID并在单个调用中返回组合结果。

  3. 在AEP中预计算:使用计算属性在配置文件级别预计算数组中的值。

  4. 单值提取:如果只需要一个值,请使用firsthead提取它。 请参阅从数组中提取单个值。

护栏和限制中了解详情。

阵列大小注意事项

大型阵列可能会影响历程性能:

  • 事件数组:将事件有效负载保持在50 KB以下
  • 自定义操作响应:响应负载应小于100KB
  • 数据集查找结果:限制查找键和返回实体的数量

完整示例:从事件数组到自定义操作 complete-example

以下是一个完整的工作流,其中显示了如何将事件数组与自定义操作结合使用。

方案:当用户放弃购物车时,将购物车数据发送到外部推荐API以获取个性化建议,然后在电子邮件中显示这些建议。

查看示例代码

步骤1:配置自定义操作

创建自定义操作“GetCartRecommendations”:

  • 方法: POST
  • URLhttps://api.example.com/recommendations
  • 请求正文
code language-json
{
  "cartItems": [
    {
      "sku": "string",
      "price": 0,
      "quantity": 0
    }
  ]
}
  • cartItems标记为类型listObjectVariable
  • 定义字段: sku (字符串)、price (数字)、quantity (整数)

请参阅配置自定义操作以了解详情。

步骤2:配置响应有效负载

在自定义操作中,配置响应:

code language-json
{
  "recommendations": [
    {
      "productId": "string",
      "productName": "string",
      "price": 0,
      "imageUrl": "string"
    }
  ]
}

使用API调用响应中了解更多信息。

步骤3:在历程中引导操作

  1. 发生购物车放弃事件后,添加自定义操作

  2. cartItems集合的高级模式下:

    code language-javascript
    @event{cartAbandonment.commerce.productListItems.all(currentEventField.quantity > 0)}
    
  3. 映射收藏集字段:

    • skuproductListItems.SKU
    • priceproductListItems.priceTotal
    • quantityproductListItems.quantity

步骤4:在电子邮件中使用响应

在电子邮件内容中,对推荐进行迭代:

code language-handlebars
<h2>We noticed you left these items in your cart</h2>
{{#each context.journey.events.cartAbandonment.productListItems as |item|}}
  <div class="cart-item">
    <p>{{item.name}} - Quantity: {{item.quantity}}</p>
  </div>
{{/each}}

<h2>You might also like</h2>
{{#each context.journey.actions.GetCartRecommendations.recommendations as |rec|}}
  <div class="recommendation">
    <img src="{{rec.imageUrl}}" alt="{{rec.productName}}" />
    <h3>{{rec.productName}}</h3>
    <p>${{rec.price}}</p>
  </div>
{{/each}}

步骤5:测试您的配置

运行实时历程之前,使用操作配置中的“发送测试请求”功能测试自定义操作,以验证构建的请求和值。

  1. 使用历程测试模式
  2. 使用包含productListItems数组的示例事件数据触发
  3. 验证自定义操作是否收到正确的数组结构
  4. 检查操作测试日志
  5. 预览电子邮件以确认两个数组均正确显示

请参阅自定义操作疑难解答以了解详情。

最佳实践 best-practices

在对上下文数据进行迭代以创建可维护、高性能个性化时,请遵循这些最佳实践。

使用描述性变量名称

选择明确指示您正在迭代的内容的变量名称。 这使得您的代码更易读取和维护。 详细了解个性化语法

查看示例代码
code language-handlebars
<!-- Good -->
{{#each products as |product|}}
{{#each users as |user|}}
{{#each recommendations as |recommendation|}}

<!-- Less clear -->
{{#each items as |item|}}
{{#each array as |element|}}

循环中的表达式片段

{{#each}}循环中使用表达式片段时,请注意,不能将循环范围的变量作为片段参数传递。 但是,片段可以访问在片段之外的消息内容中定义的全局变量。

查看示例代码

支持的模式 — 使用全局变量:

code language-handlebars
{% let globalDiscount = 15 %}

{{#each context.journey.actions.GetProducts.items as |product|}}
  <div class="product">
    <h3>{{product.name}}</h3>
    {{fragment id='ajo:fragment123/variant456' mode='inline'}}
  </div>
{{/each}}

片段可以引用globalDiscount,因为它已在消息中全局定义。

不支持 — 传递循环变量:

code language-handlebars
{{#each products as |product|}}
  <!-- This will NOT work as expected -->
  {{fragment id='ajo:fragment123/variant456' currentProduct=product}}
{{/each}}

解决方法:将个性化逻辑直接包含在循环中,而不是使用片段,或者在循环之外调用片段。

了解有关在循环中使用表达式片段的更多信息,包括详细示例和其他解决方法。

处理空数组

当数组为空时,使用{{else}}子句提供回退内容。 了解有关辅助函数的更多信息

查看示例代码
code language-handlebars
{{#each context.journey.actions.GetRecommendations.items as |item|}}
  <div>{{item.name}}</div>
{{else}}
  <p>No recommendations available at this time.</p>
{{/each}}

与条件帮助程序组合

在条件内容的循环中使用{{#if}}。 详细了解条件规则,并查看自定义操作响应数据集查找部分中的示例。

查看示例代码
code language-handlebars
{{#each context.journey.actions.GetProducts.items as |product|}}
  <div class="product">
    <h3>{{product.name}}</h3>
    {{#if product.onSale}}
      <span class="badge">On Sale!</span>
    {{/if}}
    {{#if product.newArrival}}
      <span class="badge">New</span>
    {{/if}}
  </div>
{{/each}}

限制性能迭代

对于大型数组,请考虑限制迭代次数:

查看示例代码
code language-handlebars
<!-- Display only first 5 items -->
{{#each context.journey.actions.GetProducts.items as |product|}}
  {{#if @index < 5}}
    <div>{{product.name}}</div>
  {{/if}}
{{/each}}

访问阵列元数据

Handlebars在循环中提供特殊变量,帮助处理高级迭代模式:

  • @index:当前迭代索引(基于0)
  • @first:第一个迭代为True
  • @last:最后一个迭代为True
查看示例代码
code language-handlebars
{{#each products as |product|}}
  <div class="product {{#if @first}}featured{{/if}}">
    {{@index}}. {{product.name}}
  </div>
{{/each}}
NOTE
这些Handlebars变量(@index@first@last)仅在消息个性化的{{#each}}循环中可用。 若要在历程表达式中使用数组(例如,在传递到自定义操作之前从数组获取第一项),请使用数组函数,如headfirstall。 有关详细信息,请参阅在历程表达式中使用数组

疑难解答 troubleshooting

存在迭代问题? 本节介绍常见问题和解决方案。

数组未显示

问题:您的数组迭代未显示任何内容。

查看可能的原因和解决方案

可能的原因和解决方案

  1. 不正确的路径:根据上下文源验证数组的确切路径:

    • 对于事件context.journey.events.<event_ID>.<fieldPath>
    • 对于自定义操作context.journey.actions.<actionName>.<fieldPath>
    • 对于数据集查找context.journey.datasetLookup.<activityID>.entities
  2. 数组为空:添加{{else}}子句以检查数组是否没有数据。 有关示例,请参阅最佳实践

  3. 数据尚不可用:请确保在历程流中的消息活动之前已执行自定义操作、事件或数据集查找活动。

语法错误

问题:表达式验证失败或未呈现消息。

查看常见错误

常见错误

  • 缺少结束标记:每个{{#each}}都必须有一个{{/each}}。 请查看Handlebars迭代语法以了解正确结构。
  • 变量名称不正确:请确保在整个块中一致使用变量名称。 有关命名惯例,请参阅最佳实践
  • 路径分隔符不正确:使用点(.)而不使用斜线或其他字符

表达式片段无法在循环中使用

问题:表达式片段在{{#each}}循环中使用时不显示预期的内容,或显示空/意外的输出。

查看可能的原因和解决方案

可能的原因和解决方案

  1. 尝试将循环变量作为参数传递:表达式片段不能将循环范围的变量(如当前迭代项)作为参数接收。 这是已知的限制。

    解决方案:使用以下变通方法之一:

    • 在片段可以访问的消息中定义全局变量
    • 将个性化逻辑直接包含在循环中,而不是使用片段
    • 如果不需要特定于循环的数据,则调用循环外部的片段
  2. 片段需要不可用的参数:如果您的片段设计来接收特定的输入参数,那么当这些参数无法从循环中传递时,它将无法正常工作。

    解决方案:重构您的方法,以使用片段可以访问的全局变量。 有关示例,请参阅最佳实践 — 循环中的表达式片段。

  3. 变量作用域不正确:片段可能正在尝试引用仅存在于循环作用域中的变量。

    解决方案:定义片段在消息级别(循环外部)需要的任何变量,以便它们可全局访问。

了解有关在循环中使用表达式片段的更多信息,包括详细的说明、示例和推荐的模式。

测试迭代

使用历程测试模式验证您的迭代。 在使用自定义操作数据集查找时,这一点尤其重要:

查看测试步骤
  1. 测试模式下开始您的历程
  2. 使用示例数据触发事件或自定义操作
  3. 检查消息预览以验证迭代是否正确显示
  4. 查看测试模式日志中是否有任何错误(请参阅自定义操作测试模式日志

Personalization基础知识: 个性化入门 | 添加个性化 | Personalization语法 | 辅助函数 | 创建条件规则

历程配置: 关于事件 | 配置自定义操作 | 将集合传递到自定义操作参数 | 在自定义操作中使用API调用响应 | 自定义操作疑难解答 | 在历程中使用Adobe Experience Platform数据 | 在历程中使用补充标识符 | 护栏和限制 | 测试您的历程

表达式函数历程: 高级表达式编辑器 | 集合管理函数(第一个、全部、最后一个) | 列出函数 (serializeList、筛选器、排序) | 数组函数 (头、尾)

Personalization使用案例: 购物车放弃电子邮件 | 订单状态通知

邮件设计:电子邮件设计入门 | 创建推送通知 | 创建短信消息 | 预览和测试您的内容

AI Knowledge Reference

This section contains structured knowledge intended to support interpretation, retrieval, and question answering related to this topic.

For complete understanding, this information should be combined with the documentation on this page. Neither source is intended to stand alone; the page describes the feature, while this section provides additional context that helps disambiguate terminology, intent, applicability, and constraints.

  • TL;DR: This page explains how to use Handlebars {{#each}} syntax to loop over arrays from contextual sources — events, custom action responses, dataset lookups, and technical properties — in message personalization, and how to work with arrays in journey expression syntax when configuring journey activities.

Intents:

  • Iterate over event array data (e.g., cart items, order items) in message personalization using {{#each}}
  • Iterate over custom action response arrays (e.g., product recommendations) in messages
  • Iterate over dataset lookup result arrays in messages
  • Combine data from multiple contextual sources in a single personalized message
  • Pass array values to custom action parameters using journey expression syntax
  • Use arrays as lookup keys in Dataset Lookup activities
  • Apply best practices for empty array fallbacks, variable naming, performance, and expression fragment scoping

Glossary:

  • Handlebars: A templating language used in Journey Optimizer message personalization for iteration ({{#each}}) and conditional rendering ({{#if}}). (product-specific)
  • {{#each}} helper: Handlebars syntax for iterating over an array; each iteration exposes the current item via a named variable (e.g., |product|). (product-specific)
  • Contextual data: Data available at message send time from journey sources — events, custom action responses, dataset lookups, and journey technical properties — as opposed to static profile attributes. (product-specific)
  • currentEventField: A reference used in journey expressions (not Handlebars) to refer to each item in an event array during filtering or mapping operations.
  • currentActionField: Used in journey expressions to refer to each item in a custom action response collection.
  • currentDataPackField: Used in journey expressions to refer to each item in a data source collection.
  • serializeList: A journey expression function that converts a list of values into a delimited string (e.g., comma-separated), suitable for use as a query parameter.
  • Supplemental identifier: A journey-level identifier that distinguishes concurrent journey instances triggered by the same profile; used to filter an array to the item relevant to the current instance.

Guardrails:

  • Journeys cannot create dynamic loops where one action node executes multiple times per array item — this is by design to prevent performance issues. Pass the entire array or a serialized list to a single custom action instead.
  • Keep event payloads under 50KB total.
  • Custom action response payloads should be under 100KB.
  • Limit the number of dataset lookup keys and returned entities for performance.
  • Expression fragments cannot receive loop-scoped variables (e.g., the current {{#each}} iteration item) as parameters — this is a known limitation. Use global variables or inline logic instead.
  • Numeric event IDs must be wrapped in backticks in expression paths (e.g., context.journey.events.`1697323153`.fieldName); without backticks, the PQL parser raises a syntax error.

Terminology:

  • Canonical name: Handlebars iteration — variants: {{#each}} loop, each loop, array iteration
  • Do not confuse: Handlebars {{#each}} syntax (used in message content for iteration and display) ≠ journey expression syntax (used in journey activity configuration — uses functions like first, all, serializeList)
  • Do not confuse: currentEventField (journey expressions over event arrays) ≠ currentActionField (custom action response collections) ≠ currentDataPackField (data source collections)
  • Do not confuse: @index / @first / @last (Handlebars special variables, only available within {{#each}} loops in message content) ≠ first / head functions (journey expression functions for extracting single items, used in journey activity configuration)

FAQ:

  • Q: What is the difference between Handlebars syntax and journey expression syntax when working with arrays? — Handlebars {{#each}} is used in message content for iteration and display. Journey expression syntax — using functions like first, all, and serializeList — is used in journey activity configuration (e.g., custom action parameters, conditions). They are distinct syntaxes used in different contexts.
  • Q: Can I loop a journey action node so it executes once per array item? — No. Journeys cannot create dynamic loops that execute an action node multiple times per item. Instead, pass the entire array or a serialized list to a single custom action that processes all items, or use external aggregation.
  • Q: Can I pass the current loop item to an expression fragment inside a {{#each}} loop? — No. Expression fragments cannot receive loop-scoped variables as parameters. Use global variables defined outside the loop, or include the personalization logic directly within the loop instead of using a fragment.
  • Q: How do I display fallback content when an array is empty? — Use the {{else}} clause within the {{#each}} block. Content inside {{else}} is rendered when the array has no items.
  • Q: What do @index, @first, and @last mean inside a {{#each}} loop? — These are special Handlebars variables available only within {{#each}} loops in message content: @index is the 0-based current iteration index, @first is true for the first iteration, and @last is true for the last iteration.
recommendation-more-help
journey-optimizer-help