Arrays Lists Snippets
Custom Code Snippets — Arrays & Lists
Copy-paste examples for working with arrays inside a Custom Code workflow step — connected records, line items, tag lists, log entries, anything iterable. The Arr helper covers the high-leverage operations; standard Array.prototype methods (map, filter, reduce) are also fully available.
The Arr helper covers first, last, sum, avg, unique, flatten, chunk, shuffle, sortBy, groupBy, pluck, find, filter, map.
Sum a numeric column from connected records
// Inputs: line_items (action_record_obj or connected_obj — an array)
const items = Array.isArray(params["line_items"]) ? params["line_items"] : [];
const total = Arr.sum(items.map(i => Number(i.price) * Number(i.qty || 1)));
returnData("order_total", Num.round(total, 2));
returnData("line_count", items.length);
Pick a random welcome message
const messages = [
"Welcome aboard!",
"Glad you're here.",
"Let's get you started.",
"Great to see you!"
];
returnData("welcome", messages[Num.randomInt(0, messages.length - 1)]);
Group records by a field
// Inputs: orders (array of objects, each with a `status`)
const orders = Array.isArray(params["orders"]) ? params["orders"] : [];
const byStatus = Arr.groupBy(orders, "status");
returnData("by_status", byStatus);
returnData("paid_count", (byStatus.paid || []).length);
returnData("unpaid_count", (byStatus.unpaid || []).length);
Find the most recent item
const items = Array.isArray(params["activity"]) ? params["activity"] : [];
const sorted = Arr.sortBy(items, "created_at").reverse();
returnData("latest", sorted[0] || null);
returnData("latest_at", sorted[0] ? sorted[0].created_at : null);
Pluck one field across an array
// Turn [{id:1, email:"a@b"}, ...] into ["a@b", ...]
const emails = Arr.pluck(params["contacts"] || [], "email");
returnData("emails", Arr.unique(emails));
returnData("emails_csv", emails.join(", "));
Count unique tags across many posts
const tags = Arr.flatten((params["posts"] || []).map(p => p.tags || []));
returnData("unique_tags", Arr.unique(tags));
returnData("tag_count", Arr.unique(tags).length);
Top N items by a numeric field
// Inputs: customers (array of {name, lifetime_value}), limit (custom_val 5)
const customers = Array.isArray(params["customers"]) ? params["customers"] : [];
const limit = Number(params["limit"]) || 5;
const top = Arr.sortBy(customers, "lifetime_value")
.reverse()
.slice(0, limit);
returnData("top_customers", top);
returnData("top_names", Arr.pluck(top, "name").join(", "));
Items in the bottom 10% by score
const rows = Array.isArray(params["rows"]) ? params["rows"] : [];
const cut = Math.max(1, Math.floor(rows.length * 0.10));
const worst = Arr.sortBy(rows, "score").slice(0, cut);
returnData("bottom_10_percent", worst);
returnData("count_flagged", worst.length);
Min, max, average of a numeric column
const values = (params["readings"] || [])
.map(r => Number(r.value))
.filter(n => !isNaN(n));
returnData("count", values.length);
returnData("min", values.length ? Math.min(...values) : null);
returnData("max", values.length ? Math.max(...values) : null);
returnData("avg", values.length ? Num.round(Arr.avg(values), 2) : null);
Chunk an array into batches of N
// Useful for paginating large lists into smaller messages
const all = Array.isArray(params["records"]) ? params["records"] : [];
const batches = Arr.chunk(all, 100);
returnData("batch_count", batches.length);
returnData("first_batch", batches[0] || []);
Merge two arrays of records, dedupe by id
const a = params["list_a"] || [];
const b = params["list_b"] || [];
const seen = new Set();
const merged = [];
for (const r of [...a, ...b]) {
if (!r || !r.id || seen.has(r.id)) continue;
seen.add(r.id);
merged.push(r);
}
returnData("merged", merged);
returnData("count", merged.length);
Turn an array of objects into CSV text
// Inputs: rows (array of {name, email, plan})
const rows = Array.isArray(params["rows"]) ? params["rows"] : [];
if (!rows.length) {
returnData("csv", "");
return;
}
const cols = Object.keys(rows[0]);
const escape = v => {
const s = String(v == null ? "" : v);
return /[",\r\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
};
const lines = [cols.join(",")];
for (const r of rows) {
lines.push(cols.map(c => escape(r[c])).join(","));
}
returnData("csv", lines.join("\n"));
returnData("row_count", rows.length);
Find items in A that aren't in B (and vice versa)
const a = (params["a"] || []).map(String);
const b = (params["b"] || []).map(String);
const inAOnly = a.filter(x => !b.includes(x));
const inBOnly = b.filter(x => !a.includes(x));
returnData("only_in_a", inAOnly);
returnData("only_in_b", inBOnly);
returnData("identical", inAOnly.length === 0 && inBOnly.length === 0);
Pivot a list into a {label: count} object
// Counts occurrences of each value in a column
const rows = params["rows"] || [];
const field = params["field"] || "status";
const counts = {};
for (const r of rows) {
const k = String(r[field] || "unknown");
counts[k] = (counts[k] || 0) + 1;
}
returnData("counts", counts);
returnData("top_label", Object.entries(counts).sort((a, b) => b[1] - a[1])[0]?.[0] || null);
Rolling 7-day total
// Inputs: events (array of {date, amount})
const events = Array.isArray(params["events"]) ? params["events"] : [];
const cutoff = DateTime.addDays(DateTime.now(), -7);
const recent = events.filter(e => new Date(e.date) >= new Date(cutoff));
const total = Arr.sum(recent.map(e => Number(e.amount) || 0));
returnData("count_7d", recent.length);
returnData("total_7d", Num.round(total, 2));
Shuffle an array (raffle picker)
const entries = Array.isArray(params["entries"]) ? params["entries"] : [];
const winners = Arr.shuffle(entries.slice()).slice(0, 3);
returnData("winners", winners);
returnData("winner_emails", Arr.pluck(winners, "email").join(", "));
We'd love to hear your feedback.