Data Mapping — Source resolution
Source resolution answers the question "which source column(s) become this field on the lens?" — before transforms run, before null handling.
from: undefined (identity)
Omit from and the source column name is the same as the output field
name:
Identity is the default. Most fields on most lenses use it.
from: string (rename)
Point at a different source column:
The source table still contains name_en; the index-level view is
productName. Callers of beam.products.query(...) get row.productName,
never row.name_en.
from: string[] (merge)
Combine multiple source columns into one output field. Requires merge.
merge: 'concat'
Joins non-null parts with a separator. Nulls are dropped; an empty
result is the empty string.
separator is required when merge: 'concat'. Common values:
| Separator | Use case |
|---|---|
' ' | "Priya Shah" |
', ' | "Oakland, CA" |
' · ' | "Section · Article · Heading" (dotted join) |
'\n' | Multi-line description assembled from parts |
merge: 'coalesce'
Returns the first non-null part. If every part is null, the result is
null (then nullAs kicks in if set).
No separator needed — coalesce returns one value as-is.
Transform runs on the resolved value
Crucial detail: when you use from: string[] + merge + transform,
the transform runs on the merged string, not each part individually.
Not on 'Priya' and 'Shah' separately. If you need per-part
transformation (e.g. lowercase each part before merging), declare them
as separate fields first:
What happens when from doesn't exist
Validation does NOT check this at config time. Your lens will push
successfully with from: 'typo_column' on every field. At ingest time:
- The bridge fetch doesn't raise — it just doesn't return that column.
- Mapping resolves to
undefined. undefinedAskicks in (if set).- If
undefinedAsisn't set,nullAsdoesn't either (undefined ≠ null). - The output row has
undefinedfor that field, which downstream code reads as missing.
Catch this in testing. The CLI's semilayer generate emits TypeScript
types from your lens config — if you run codegen against a freshly
pushed lens and query a field whose from is wrong, you get typed
undefineds at runtime, but no compile-time signal. The right fix is
always to reconcile the mapping against the actual source schema before
shipping.
When from is an array of 1
Arrays of length 1 are a validation error. Use from: 'first_name'
(string) instead. If you genuinely need the single-source-with-merge
shape (e.g. you want a placeholder for adding more sources later),
add the second column now and tolerate one of them always being null.
Ordering matters
Source column order in from: [] determines:
concat: the order of the output string's parts.coalesce: the priority — the first non-null wins.
Changing the order is semantically meaningful — ['first_name', 'last_name']
produces 'Priya Shah'; ['last_name', 'first_name'] produces
'Shah Priya'. Keep them aligned with the rendering intent.
Next: Transforms — what you can do to the resolved value.