Task Reference
lookup
Resolve foreign keys and enrich records with a fallback chain of single-row lookups across SQL and MongoDB Connectors.
lookup
Enriches each input item by trying an ordered chain of single-row lookups against SQL or MongoDB Connectors and merging the first match into the record.
When to use it
Use lookup for cross-store joins and foreign-key resolution, such as resolving an email to a staged account row before writing a related record. For destination-ID dedup lookups against the mapping store, prefer sync_record (or get_destination_id in existing tasks).
Configuration
| Key | Type | Required | Default | Description |
|---|---|---|---|---|
keys |
array | Yes | — | Ordered lookup attempts. The step stops at the first match. An empty list fails with lookup requires at least one keys entry. |
keys[].connector |
string | Yes | — | SQL (sqlite, mssql, mysql, postgres) or MongoDB Connector slot. Other types fail with lookup requires a SQL or MongoDB connector. |
keys[].table |
string | For SQL | — | Table to query. One of table or collection is required per key. |
keys[].collection |
string | For MongoDB | — | Collection to query. One of table or collection is required per key. |
keys[].match |
object | Yes | — | Filter passed to find_one. A string value starting with $record. is replaced by that field's value from the input item. |
keys[].select |
string[] | No | — | Columns to return. SQL: passed as select; MongoDB: converted to a projection. |
as |
string | No | — | Nest the matched row under this key on the output. Omitted, the row's fields are merged into the record. |
required |
boolean | No | — | When true and no key matches, the item is dropped (nothing emitted). |
emit |
string | No | — | matched_only or all. matched_only drops unmatched items, same as required: true. |
Example
name: resolve_ticket_accounts
connectors:
source:
type: mongodb
staging:
type: sqlite
steps:
- name: read_tickets
type: call_method
config:
connector: source
method: find
args:
collection: tickets
- name: resolve_account
type: lookup
config: |
{
"keys": [
{
"connector": "staging",
"table": "accounts",
"match": { "email": "$record.requester_email" },
"select": ["destination_id", "name"]
},
{
"connector": "staging",
"table": "accounts",
"match": { "domain": "$record.requester_domain" }
}
],
"as": "account",
"required": true
}Behavior notes
- Fallback chain. Keys are tried in order with the Connector's
find_onemethod; the first row found wins and later keys are not queried. Use the chain to express "match by email, else by domain" style resolution. $record.references. Only string values inmatchthat start with$record.are resolved against the input item; everything else is passed as a literal. The config as a whole can still be a JSONata string when values need expressions.- Merge semantics. With
as, the match is attached under one key and the rest of the record is untouched. Withoutas, the row's fields are merged into the record and overwrite same-named input fields. - No match. With
required: trueoremit: matched_onlythe item is dropped from the stream. Otherwise the item passes through without enrichment. - Non-object input (a bare string or number) is wrapped as
{ value: <input> }before matching and merging. - Lookups are issued per item on every pass; the step does not cache results.
Related
- sync_record — dedup lookups against the mapping store
- transform — enrich with
$callMethodwhen a chain is not needed - Migration playbook — where cross-store joins fit in a migration