Skip to main content

Map arrays with iteration scopes

Order lines, invoice items, tags — transactional data lives in arrays, and mapping them is more than connecting two paths. Should each source element become a target element? Should a list collapse into one value (a total, a count, a joined string)? Should a single value be wrapped into an array? Cardinality-aware array mapping answers this with one concept: the iteration scope — a rule that pairs a source array with a target, owns the per-element attribute mappings inside it, and carries an explicit strategy for how elements correspond.

All three array scenarios ride on the same scope:

ScenarioStrategyBadge
Array → array (element-wise)positional, keyed, or filteredN→N
Array → single valuecollapse + a collapse modeN→1
Single value → arrayconstruct1→N

By the end of this page you will have:

  • Enabled the array-mapping canvas surface.
  • Created an iteration scope by mapping [*] paths — manually and via Auto-map.
  • Read the scope chip: strategy, element-attribute count, and status.
  • Collapsed an array into a single target value and overridden the collapse mode.
  • Confirmed your overrides survive an Auto-map re-run.
You'll need
  • A MapCraft project open at /mapcraft/{projectId} with source and target schemas attached.
  • At least one array on each side — e.g. source order.lines[*] and a target invoice.items[*], plus a scalar target like invoice.total for the collapse scenario.
  • NEXT_PUBLIC_MAPCRAFT_ARRAY_MAPPING=true set on the frontend deployment (see Step 1).

Step 1 — Enable the canvas surface

The scope chips ship behind a progressive-rollout flag:

NEXT_PUBLIC_MAPCRAFT_ARRAY_MAPPING=true # also accepts 1 / yes / on
Flag changes require a rebuild

NEXT_PUBLIC_* values are inlined into the client bundle at build time — flipping the flag means redeploying the frontend.

The flag gates only the visual chips. The backend always groups array ([*]) edges into iteration scopes, so mappings you create while the flag is off are already scope-correct when the chips appear.


Step 2 — Create a scope by drawing an array edge

Drag a connection from an array-nested source field to an array-nested target field — for example:

order.lines[*].sku → invoice.items[*].sku

Because both paths contain [*], MapCraft doesn't create a bare scalar edge. It folds the connection into an iteration scope keyed by the target array container (invoice.items), and registers sku → sku as an element-attribute rule inside it.

Draw a second array edge to the same target container — order.lines[*].qty → invoice.items[*].quantity — and it attaches to the same scope. One scope per target array; N attribute rules inside it.

On the canvas, the scope renders as a chip with an [] badge: order.lines → invoice.items, an N→N marker, and an attribute count (2 attrs).


Step 3 — Or let Auto-map pair the arrays

Click Auto-map. After its scalar tiers, Auto-map pairs source and target array containers, recurses into the element attributes, and infers how elements correspond:

  • keyed — elements match by an identifying attribute (id/sku/code-like fields are detected as keys).
  • positional — elements match by index.

The resulting scopes arrive with origin = "ai" and render the same chips as Step 2. Hover a chip to read the scope's natural-language description.


Step 4 — Pick the right strategy

Every chip has an inline strategy picker:

StrategyUse when
positionali-th source element maps to i-th target element.
keyedElements pair by a key attribute regardless of order.
filteredOnly elements passing a condition map across.
constructA single source value is wrapped into a target array.
collapseThe whole array reduces to one target value (Step 5).

Changing the strategy saves immediately and stamps the scope origin = "manual" — the chip gains an edited badge (hover text: "Edited by you — preserved across Auto-Map re-runs").


Step 5 — Collapse an array into one value

For an array → scalar target (order.lines[*].amount → invoice.total):

  1. Map the array-nested source to the scalar target. The scope is created with strategy collapse and the badge flips to N→1.
  2. When Auto-map authored the scope, it pre-applies the recommended collapse mode (numeric amounts → sum). You can override it.
  3. With collapse selected, a second dropdown appears — the collapse mode:
ModeResult
first / lastOne element's value.
sum / avg / min / maxNumeric reduction.
countElement count.
concatValues joined into one string.
distinctDe-duplicated values.
filterValues passing a condition.
Exports stay correct everywhere

Scope rules compile per export target: Python list comprehensions, JSONata $map/built-ins, and SQL LATERAL jsonb_array_elements — including nested arrays. What you preview in MapCraft is the same logic FlowBridge runs and the same SQL your warehouse executes.


Step 6 — Re-run Auto-map safely

Iteration scopes follow the same origin rules as combined N→1 rules: re-running Auto-map regenerates only origin = "ai" scopes. Any scope you created manually or overrode (strategy or collapse mode) is origin = "manual" and is left untouched — the edited badge tells you which ones those are.


Verify

Array mapping is working end-to-end if:

CheckWhere to look
One scope per target arrayTwo [*] edges into the same target container produce one chip with 2 attrs, not two chips.
The badge matches the scenarioN→N for element-wise, N→1 for collapse, 1→N for construct.
The scope verifiedChip is green. Amber means the verifier flagged it for review; sky/blue means verification is still pending.
Overrides persistChange a strategy, re-run Auto-map, and the chip still shows your choice plus the edited badge.

Troubleshooting

No chips appear on the canvas. The flag is off in this build — confirm NEXT_PUBLIC_MAPCRAFT_ARRAY_MAPPING=true was present at build time and redeploy. Your scopes still exist server-side and will render once the flag is on.

I drew a second array edge and no new chip appeared. By design: edges sharing the same target array container fold into the existing scope. Check the chip's attribute count — it should have incremented.

The chip is amber (needs review). The verifier's cardinality guard flagged the scope — typically the rule's output cardinality doesn't match the target (e.g. an array-typed target receiving a single value). Revisit the strategy; collapse and construct are the usual fixes for mismatched sides.

My collapse mode keeps showing sum but I wanted concat. Pick concat in the collapse-mode dropdown — the change persists as a manual override. If you instead re-ran Auto-map before overriding, the ai-origin scope was regenerated with the recommendation; override it and it will stick from then on.


What's next