Skip to content

Working with Data

QuickFlo provides a set of data transformation steps for processing arrays of items — filtering rows, mapping fields, aggregating values, sorting, grouping, and joining datasets. These steps work like a data pipeline where each step transforms the output of the previous one.

Data steps that iterate over items expose these context variables, which you can use in template expressions and conditions:

VariableDescription
$itemThe current item object
$thisAlias for $item (useful for primitive arrays)
$indexZero-based iteration index
$isFirsttrue for the first item
$isLasttrue for the last item

The map step (data.map) transforms each item in an array using template expressions.

Map step field mappings with output field names and template expressions
FieldDescription
itemsArray of items to transform
mapObject defining field mappings with template expressions
includeOriginalIf true, merge transformed fields into the original item

Rename and compute fields:

Output FieldExpression
fullName{{ $item.firstName }} {{ $item.lastName }}
isAdult{{ $item.age | gte: 18 }}
email{{ $item.email | downcase }}

Extract a single value per item (flatten to primitives):

Output FieldExpression
$value{{ $item.id }}

Output: [1, 2, 3, ...] — an array of IDs instead of objects. Use $value as the field name to unwrap items into primitives.

Add a row number:

Output FieldExpression
rowNum{{ $index | plus: 1 }}
name{{ $item.name }}

Keep original fields and add computed ones:

Set includeOriginal to true and only define the new fields:

Output FieldExpression
displayName{{ $item.firstName }} {{ $item.lastName }}

All original fields are preserved and displayName is added.

{{ transform-users.items }} // transformed array
{{ transform-users.count }} // number of items
{{ transform-users.errors }} // any per-field errors

The filter step (data.filter) keeps items from an array that match a set of conditions.

FieldDescription
itemsArray of items to filter
filterConditions that items must match to be kept
Visual condition builder with ALL/ANY grouping, field expressions, and operators

Conditions are built using the visual condition builder. Each condition has three parts:

  1. Left value — typically a template expression like {{ $item.status }}
  2. Operatorequals, not equals, greater than, less than, contains, etc.
  3. Right value — the value to compare against (literal or template expression)

You can combine multiple conditions with ALL (every condition must match) or ANY (at least one must match), and nest condition groups for complex logic.

Keep active users:

Match ALL of these conditions:

  • {{ $item.status }} equals active

Keep adults with recent activity:

Match ALL of these conditions:

  • {{ $item.age }} greater than 18
  • {{ $item.lastLoginDays }} greater than 0
  • {{ $item.isDeleted }} equals false

Keep items from specific regions:

Match ANY of these conditions:

  • {{ $item.region }} equals US
  • {{ $item.region }} equals CA
  • {{ $item.region }} equals UK
{{ filter-active.items }} // items that matched
{{ filter-active.count }} // number of matched items
{{ filter-active.filteredCount }} // number of items removed

The reduce step (data.reduce) aggregates an array into summary values — like SQL aggregate functions.

FieldDescription
itemsArray of items to aggregate
reduceNamed aggregation operations
OperationDescriptionField
countCount items (optionally with a condition)
sumSum a numeric field$item.amount
avgAverage a numeric field$item.score
minMinimum value$item.price
maxMaximum value$item.price
collectGather values into an array$item.email
uniqueUnique values$item.status
countUniqueCount distinct values$item.userId
joinJoin values with separator$item.name (separator: , )
firstFirst value$item.email
lastLast value$item.status

Each aggregation is given a name (the result key) and configured with an operation and a field to operate on.

Reduce step with named aggregation operations configured in the visual editor

Multiple aggregations at once:

Result NameOperationFieldCondition
totalRevenuesum$item.amount
avgOrderValueavg$item.amount
orderCountcount
uniqueCustomerscountUnique$item.customerId
highValueCountcount$item.amount greater than 1000

Conditional aggregation:

Aggregations like count and sum can include an optional condition to only include items that match.

{{ summarize-orders.results.totalRevenue }}
{{ summarize-orders.results.avgOrderValue }}
{{ summarize-orders.results.uniqueCustomers }}
{{ summarize-orders.totalItems }}

The sort step (data.sort) orders items by one or more fields with type-aware comparison.

FieldDescription
itemsArray to sort
sortSort criteria (field, direction, type)
nullHandlingWhere to place null values: first or last

Each sort criterion has:

FieldDescription
fieldField name to sort by
directionasc or desc
typestring, number, date, or auto

Sort by creation date (newest first), then by name alphabetically:

FieldDirectionType
createdAtdescdate
nameascstring
{{ sort-users.items }} // sorted array
{{ sort-users.count }}

The group by step (data.group-by) groups items by field value(s) with optional aggregations — like SQL GROUP BY.

FieldDescription
itemsArray to group
groupByField name(s) to group by
aggregationsSame aggregation operations as the Reduce step
includeItemsIf true, include the raw items array in each group

Group sales data by region with aggregations:

Group by: region

Aggregation NameOperationField
totalSalessum$item.amount
avgDealSizeavg$item.amount
repscollect$item.repName
{{ group-by-region.groups }} // array of group objects
{{ group-by-region.totalGroups }} // number of groups
{{ group-by-region.totalItems }} // total items processed

Each group contains:

{
"key": "US",
"count": 42,
"aggregations": {
"totalSales": 125000,
"avgDealSize": 2976.19,
"reps": ["Alice", "Bob", "Carol"]
}
}

You can group by multiple fields (e.g., region and productLine), in which case each group’s key becomes an array like ["US", "Enterprise"].


The split step (data.split) divides an array into chunks or partitions.

Split into fixed-size batches — useful for processing large datasets in manageable pieces:

FieldValue
items{{ fetch-all.data }}
modechunk
chunkSize100

Output:

{{ split-batches.chunks }} // array of arrays
{{ split-batches.totalChunks }}
{{ split-batches.totalItems }}

Split into two groups based on a condition — items that match and items that don’t:

FieldValue
items{{ fetch-contacts.data }}
modepartition
condition{{ $item.status }} equals active

Output:

{{ partition-contacts.matching }} // items where condition is true
{{ partition-contacts.notMatching }} // items where condition is false
{{ partition-contacts.matchingCount }}
{{ partition-contacts.notMatchingCount }}

The select step (data.select) keeps only specified fields from each item — like SQL SELECT.

FieldValue
items{{ fetch-users.data }}
selectname, email, role

Output:

{{ select-fields.items }} // items with only the selected fields
{{ select-fields.count }}
{{ select-fields.fields }} // ["name", "email", "role"]

The join step (data.join) combines two arrays on matching key fields — like a SQL JOIN.

TypeDescription
innerOnly items that match in both arrays
leftAll from left array, matching from right
rightAll from right array, matching from left
fullAll items from both arrays

Join orders with customers on customerId = id, prefixing customer fields with customer_ to avoid name collisions:

FieldValue
left{{ fetch-orders.data }}
right{{ fetch-customers.data }}
leftKeycustomerId
rightKeyid
joinTypeleft
rightPrefixcustomer_

Data steps are most powerful when chained together. Each step’s output feeds into the next:

fetch-data → filter-active → map-fields → sort-by-date → split-batches → for-each → process

Example pipeline:

  1. Filter to keep only active records
  2. Map to transform field names and compute values
  3. Sort by date descending
  4. Split into batches of 100
  5. For-each over batches to process in parallel
// Step 1: filter
{{ filter-active.items }} // filtered array
// Step 2: map (takes filter output)
{{ map-fields.items }} // transformed array
// Step 3: sort
{{ sort-results.items }} // sorted array
// Step 4: split into batches
{{ split-batches.chunks }} // array of 100-item arrays
{{ split-batches.totalChunks }} // number of batches