Skip to content

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 → ... → compile
TierDescriptionSchema Derivation
Tier 1 — DeclarativeJSON-serializable AST. Supports lineage tracing, schema derivation, source map remapping.Full
Tier 2 — OpaqueClosure-based (apply, derive). Records input/output in lineage but is opaque to schema derivation.Limited

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 }))

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'} } }

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'),
],
}))

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 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),
}))

Key-level operations on the output.

.mapOut($ => $.rename({ firstName: 'first_name', lastName: 'last_name' }))
.mapOut($ => $.pick(['name', 'email']))
.mapOut($ => $.omit(['_internal', 'debug']))

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'))

.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',
})
)
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()
TransformDescriptionSchema Derivation
groupByRestructure array into keyed record or entriesFull
indexByConvert array to record by unique keyFull
aggregateCompute sum, count, avg, min, max, first, last, collectFull
nestMove flat properties into a sub-objectFull
unnestFlatten nested properties up to parentFull
sortSort array by field(s)Unchanged
filterFilter array by declarative predicateUnchanged
renameRename output keysFull
pickKeep only specified fieldsFull
omitRemove specified fieldsFull
deriveComputed field from output (opaque function)Type hint
pivotTurn rows into columnsPartial
applyOpaque function (Tier 2 fallback)Opaque