$items — Items Directive
Provides aggregate operations and transformations over the full input item collection — count, filter, map, sort, and projection without requiring a JavaScript engine.
| Property | Value |
|---|---|
| Directive name | items |
| Required isolation level | Safe |
| Project | NodeData.Services |
| Data source | INodeExecutionData.InputItems |
| Use case | Collection-level operations that would otherwise require $js |
Operations Reference
| Path / Operation | Returns | Example |
|---|---|---|
$items.count | Number | Total items in input collection |
$items.isEmpty | Boolean | true if no items |
$items.first.field | Any | Field from the first item |
$items.last.field | Any | Field from the last item |
$items.sum.fieldName | Decimal | Sum of all items' numeric field |
$items.avg.fieldName | Decimal | Average of all items' numeric field |
$items.min.fieldName | Decimal | Minimum value of a numeric field |
$items.max.fieldName | Decimal | Maximum value of a numeric field |
$items.pluck.fieldName | JSON Array | Array of a single field from all items |
$items.distinct.fieldName | JSON Array | Unique values of a field across all items |
$items.all | JSON Array | Full input collection as JSON |
$items.countWhere.field.value | Number | Count of items where field == value |
$items.sumWhere.numField.filterField.value | Decimal | Sum of numField where filterField == value |
Complex Scenarios
Scenario 1 — Payroll Batch Totals Summary
After processing a payroll batch, produce summary statistics without JavaScript:
// Email body summary node
Batch Summary — {@ $ctx.today }
Total employees processed : {@ $items.count }
Total gross pay : {@ $items.sum.grossPay } {@ $ctx.tenant.currency }
Total tax deducted : {@ $items.sum.taxDeducted } {@ $ctx.tenant.currency }
Total net pay : {@ $items.sum.netPay } {@ $ctx.tenant.currency }
Average net pay : {@ $items.avg.netPay } {@ $ctx.tenant.currency }
Highest gross : {@ $items.max.grossPay }
Lowest gross : {@ $items.min.grossPay }
Scenario 2 — Guard Against Empty Input
An IfCondition node skips processing when the input collection is empty:
// IfCondition: "Skip if no items"
{@ $items.isEmpty }
// true → skip to summary node
// false → continue to processing loop
// Alternatively: check minimum required count
{@ $js`return context.items.count >= 1` }
Scenario 3 — Extract List of Employee IDs for Audit
Pluck a single field from all items to build a list for an audit trail:
Audit node — all employee IDs processed
{@ $items.pluck.employeeId @json }
[1001, 1002, 1003, 1004, 1005]
Distinct departments in this batch
{@ $items.distinct.department @json }
["Finance","Engineering","HR"]
Scenario 4 — Conditional Count for SLA Alerting
Count how many items match an error condition and alert only when threshold exceeded:
// VariableAssignment: store the failure count
VariableName: "failureCount"
Value: {@ $items.countWhere.status.failed }
// IfCondition: alert if more than 5% failed
{@ $js`
const failed = parseInt(context.vars.failureCount, 10);
const total = context.items.count;
return total > 0 && (failed / total) > 0.05;
` }
// Alert message
SLA BREACH: {@ $var.failureCount } of {@ $items.count } items failed (threshold: 5%)
Scenario 5 — Sum by Status for Reconciliation Report
Produce a breakdown of amounts by payment status:
// Reconciliation node fields
{
"processed": {
"count": {@ $items.countWhere.status.processed },
"amount": {@ $items.sumWhere.amount.status.processed }
},
"pending": {
"count": {@ $items.countWhere.status.pending },
"amount": {@ $items.sumWhere.amount.status.pending }
},
"failed": {
"count": {@ $items.countWhere.status.failed },
"amount": {@ $items.sumWhere.amount.status.failed }
}
}
Scenario 6 — Pass Entire Collection to an HTTP Endpoint
Send the full input collection as the body of a bulk-insert API call:
HTTP Request body — bulk insert
{@ $items.all @json }
Full JSON array of all input items — ready for a batch API endpoint
// With a wrapper object for an API that expects an envelope:
{
"batchId": "{@ $exec.executionId }",
"count": {@ $items.count },
"records": {@ $items.all @json },
"tenantId": {@ $ctx.tenant.id }
}
Common Errors
| Error | Cause | Fix |
|---|---|---|
PathNotFound: sum.fieldName | Field doesn't exist or is not numeric | Verify field name; ensure field contains numeric values; use @default:0 |
PathNotFound: first | Input collection is empty | Guard with $items.isEmpty check before accessing first/last |
ItemsError: ambiguous filter | countWhere path has wrong segment count | Path must be exactly $items.countWhere.fieldName.value |