cannectors

loop

Iterate over an array field on each record and run a nested filter chain per item.

The loop filter walks an array field on each record and runs a nested filter chain for every item. The current item is exposed under the configured itemName alias; the root record stays available as record. Use it to flatten records that carry an array of "cells", "rows", or "lines" into top-level fields without dropping to a script filter.

Minimal example

Extract a displayValue keyed by columnId into a flat record.eventId:

filters:
  - type: loop
    field: cells
    itemName: cell
    filters:
      - type: condition
        expression: "cell.columnId == 8150579298996100"
        then:
          - type: mapping
            mappings:
              - source: cell.displayValue
                target: record.eventId

Options

propertytypedefaultdescription
typerequired
"loop"Module type discriminator. Must be `loop` for this module.
id
stringUnique identifier within the pipeline.
name
stringHuman-readable name.
description
string
enabled
booleantrueWhether module is active.
tags
array<string>
onError
string"fail"Default error action. Case-insensitive; normalized to lowercase by the runtime.
fieldrequired
stringPath to the array field, relative to the input record (root record for the outermost loop, parent scope for nested loops). Supports dot notation.
itemNamerequired
stringAlias exposed to nested filters for the current item. Cannot be 'record', '_metadata', or 'loop', and must not duplicate an active parent loop alias.
filtersrequired
array<object>Nested filters executed for every item.

Scope inside the loop

Nested filters operate on a scope — a synthetic record built once per item:

KeyWhat it is
recordThe root record. Writes to record.* mutate the original record.
<itemName>The current item. Writes to <itemName>.* are persisted back into the array at the same position.
Parent aliasesEvery active parent loop alias when loops are nested.
_metadataThe root metadata. Loop iteration state lives at _metadata.loop.<itemName>.index (read-only).

The scope is built fresh per item, but record and _metadata are shared by reference — mutations are visible to subsequent items and filters after the loop.

Loop metadata

The current index is exposed at _metadata.loop.<itemName>.index:

- type: loop
  field: rows
  itemName: row
  filters:
    - type: mapping
      mappings:
        - source: _metadata.loop.row.index
          target: row.position

_metadata.loop is read-only for nested filters. Any attempt to write under that path is rejected with loop nested filters wrote to _metadata.loop which is read-only, including replacement or deletion of _metadata itself.

Nested loops

Loops can be nested. Each inner loop adds its alias to the scope and keeps every parent alias available:

- type: loop
  field: cells
  itemName: cell
  filters:
    - type: loop
      field: cell.children
      itemName: x
      filters:
        - type: condition
          expression: >-
            _metadata.loop.cell.index == 2 &&
            _metadata.loop.x.index == 0
          then:
            - type: mapping
              mappings:
                - source: x.label
                  target: record.first

Constraints on itemName:

  • Cannot be record, _metadata, or loop (reserved scope keys).
  • Cannot duplicate an active parent loop alias.

Item removal and expansion

Nested filters return …Effect on the array
Zero records for an itemItem is removed from the array.
Exactly one recordItem is updated with the result.
More than one recordPipeline fails — item expansion is out of scope in v1.

Use a nested condition + drop to remove items conditionally:

- type: loop
  field: items
  itemName: item
  filters:
    - type: condition
      expression: "item.keep == false"
      then:
        - type: drop

Non-object items

Scalar / array / null items pass through unchanged when nested filters don't touch the alias. Sub-path writes such as item.foo = ... on a non-object item are rejected to prevent silent map auto-creation by the path engine.

Examples

examples/25-loop-cells-extraction.yamlview source ↗
25-loop-cells-extraction.yaml
name: loop-cells-extraction
version: 1.0.0
description: Iterate over a cells[] array and extract values into flat record fields by columnId.
tags:
  - loop
  - smartsheet
input:
  type: httpPolling
  schedule: "*/15 * * * *"
  endpoint: https://source.example.com/api/rows
  dataField: rows
filters:
  - type: loop
    field: cells
    itemName: cell
    filters:
      - type: condition
        expression: cell.columnId == 1
        then:
          - type: mapping
            mappings:
              - source: cell.displayValue
                target: record.eventId
      - type: condition
        expression: cell.columnId == 2
        then:
          - type: mapping
            mappings:
              - source: cell.displayValue
                target: record.coordinates
      - type: condition
        expression: cell.columnId == 3
        then:
          - type: mapping
            mappings:
              - source: cell.displayValue
                target: record.customerName
  - type: remove
    target:
      - cells
output:
  type: httpRequest
  endpoint: https://destination.example.com/api/events
  method: POST
  requestMode: single

Cross-references