Output Transforms
.mapOut() applies structural transformations to the output after extraction. It supports grouping, aggregation, nesting, sorting, filtering, renaming, and more. Multiple .mapOut() calls chain sequentially.
source → mapIn → emit → mapOut → mapOut → ... → compileTwo tiers
Section titled “Two tiers”| Tier | Description | Schema Derivation |
|---|---|---|
| Tier 1 — Declarative | JSON-serializable AST. Supports lineage tracing, schema derivation, source map remapping. | Full |
| Tier 2 — Opaque | Closure-based (apply, derive). Records input/output in lineage but is opaque to schema derivation. | Limited |
groupBy
Section titled “groupBy”Restructure an array into keyed groups.
// Record format (default): array → { key: items[] }.mapOut($ => $.groupBy('transactions', 'account'))
// Entries format: array → [{key, items}].mapOut($ => $.groupBy('transactions', 'account', { format: 'entries' }))
// Remove grouping key from items.mapOut($ => $.groupBy('items', 'cat', { omitKey: true }))indexBy
Section titled “indexBy”Convert an array to a record by unique key.
.mapOut($ => $.indexBy('users', 'id'))// { users: [{id:'a', name:'Alice'}] } → { users: { a: {id:'a', name:'Alice'} } }
.mapOut($ => $.indexBy('users', 'id', { omitKey: true }))// { users: { a: {name:'Alice'} } }aggregate
Section titled “aggregate”Compute summary values from an array.
import { sum, count, avg, min, max, first, last, collect } from '@origints/core'
.mapOut($ => $.aggregate('items', { into: '', // place results as siblings of 'items' operations: [ sum('amount', 'totalAmount'), count('itemCount'), avg('amount', 'avgAmount'), ],}))nest / unnest
Section titled “nest / unnest”Move properties into or out of sub-objects.
// Move flat properties into a sub-object.mapOut($ => $.nest('address', ['street', 'city', 'zip']))
// Flatten nested properties up.mapOut($ => $.unnest('address'))
// Partial unnest — move specific fields, keep the rest nested.mapOut($ => $.unnest('address', ['street']))Sort arrays by one or more fields.
.mapOut($ => $.sort('items', 'amount')) // ascending.mapOut($ => $.sort('items', 'amount', 'desc')) // descending
// Multi-field sort.mapOut($ => $.sort('items', [ { field: 'category', direction: 'asc' }, { field: 'amount', direction: 'desc' },]))filter
Section titled “filter”Filter arrays with declarative predicates.
import { field } from '@origints/core'
.mapOut($ => $.filter('items', field('amount').gt(0)))
.mapOut($ => $.filter('items', { kind: 'and', left: field('status').equals('active'), right: field('amount').gte(100),}))rename / pick / omit
Section titled “rename / pick / omit”Key-level operations on the output.
.mapOut($ => $.rename({ firstName: 'first_name', lastName: 'last_name' })).mapOut($ => $.pick(['name', 'email'])).mapOut($ => $.omit(['_internal', 'debug']))derive
Section titled “derive”Add computed fields to the output.
.mapOut($ => $.derive( 'fullName', out => `${out.firstName} ${out.lastName}`, 'Concatenate names', { type: 'string' } // optional schema hint))Turn rows into columns.
.mapOut($ => $.pivot('metrics', { rowKey: 'quarter', columnKey: 'metric', value: 'amount',}))// [{quarter:'Q1', metric:'revenue', amount:100}, {quarter:'Q1', metric:'cost', amount:50}]// → [{quarter:'Q1', revenue: 100, cost: 50}]Opaque function fallback (Tier 2).
.mapOut($ => $.apply(out => customTransform(out), 'Custom business logic'))Scoped transforms with .at()
Section titled “Scoped transforms with .at()”.at() returns a scoped builder that applies transforms within a sub-path. The .* wildcard applies transforms to each value in a record or each element in an array.
.mapOut($ => $ .groupBy('transactions', 'account') .at('transactions.*').sort('amount', 'desc') .at('transactions.*').aggregate({ operations: [sum('amount', 'total')], into: 'self', }))Full pipeline example
Section titled “Full pipeline example”const plan = new Planner() .in(load({ transactions: [ { account: 'A', type: 'credit', amount: 100 }, { account: 'A', type: 'debit', amount: 50 }, { account: 'B', type: 'credit', amount: 200 }, ], })) .emit((out, $) => out .add('transactions', $.get('transactions').array(tx => ({ kind: 'object', properties: { account: tx.get('account').string(), type: tx.get('type').string(), amount: tx.get('amount').number(), }, }))) ) .mapOut($ => $ .groupBy('transactions', 'account') .at('transactions.*').aggregate({ operations: [sum('amount', 'total')], into: 'self', }) ) .compile()Transform reference
Section titled “Transform reference”| Transform | Description | Schema Derivation |
|---|---|---|
groupBy | Restructure array into keyed record or entries | Full |
indexBy | Convert array to record by unique key | Full |
aggregate | Compute sum, count, avg, min, max, first, last, collect | Full |
nest | Move flat properties into a sub-object | Full |
unnest | Flatten nested properties up to parent | Full |
sort | Sort array by field(s) | Unchanged |
filter | Filter array by declarative predicate | Unchanged |
rename | Rename output keys | Full |
pick | Keep only specified fields | Full |
omit | Remove specified fields | Full |
derive | Computed field from output (opaque function) | Type hint |
pivot | Turn rows into columns | Partial |
apply | Opaque function (Tier 2 fallback) | Opaque |