Accumulators (sum, count, join)

Karl Falconer ·

An accumulate block computes a single value across a collection — a total, a count, or a joined string. The result is stored in a session variable you can use later in the rule.

accumulate order_lines in order
  total: sum order_line.unit_price * order_line.qty_ordered
end

when total > 500.0 then
  set order.custom.tier to "high-value"
end

If you’ve used a spreadsheet: An accumulate block is like =SUM(B2:B100) or =COUNTA(...) or =TEXTJOIN(...). You give it a column and a function and it gives you back one value.

The shape

accumulate collection in model
  variable: function expression
  variable: function expression
end

You can compute multiple values in one block — each on its own line.

accumulate order_lines in order
  total_price: sum order_line.unit_price * order_line.qty_ordered
  item_count:  count order_line.id
  all_skus:    join order_line.sku, ", "
end

After the block, total_price, item_count, and all_skus are available as variables for the rest of the rule.

The three functions

Function What it does Returns
sum Adds up the expression for every item. A number.
count Counts the items where the expression has a value. A number.
join Concatenates the expression’s value for each item, with a separator. Text.

sum

total_price: sum order_line.unit_price * order_line.qty_ordered

The expression can be a single field or any arithmetic expression. Each item contributes; the result is the total.

count

item_count: count order_line.id
gift_wrap_count: count order_line.gift_wrap

count returns the number of items where the expression isn’t blank. For a field that’s always present (like id), this gives the total item count. For a conditional field, you get how many items have that field.

join

all_skus: join order_line.sku, ", "
options_summary: join item.label & "=" & item.value, "; "

The second argument is the separator. The first is the per-item expression — it can be a single field or a string-concat expression.

Two iteration forms

There are two ways to point an accumulate at a collection.

Form 1 — collection on a model:

accumulate order_lines in order
  ...
end

This is the most common case: iterate the named collection (order_lines) on the named model (order).

Form 2 — collection that lives directly on a field:

accumulate order_line.options
  option_summary: join item.label & "=" & item.value, ", "
end

When the collection is a field directly (not a top-level model collection), use this form. Inside the block, the loop variable is item.

Combining with loops

accumulate and for work together. Common pattern: outer for, inner accumulate, then use the result.

for order_lines in order
  accumulate order_line.options
    option_str: join item.label & "=" & item.value, ", "
  end
  set order_line.custom.options_note to "Options: " & option_str
end

For each line item, build a comma-separated string of its options and store it on the line.

Where you can use the variables

After an accumulate block, the variables it produced are available for the rest of the rule:

  • In when conditions
  • In set actions
  • In other accumulate blocks
  • In actions like route, bundle, hold
rule "Bundle high-value frequent buyers"
  accumulate order_lines in order
    total: sum order_line.unit_price * order_line.qty_ordered
    skus: count order_line.id
  end

  when
    total > 500.0 and skus > 3
  then
    bundle order using order.external_customer_id waiting 2h
    set order.notes to "High-value: $" & total as text & " (" & skus as text & " items)"
  end
end

Limitations

  • Only sum, count, join. No average, max, min, percentile. For an average, you can compute sum / count after the block:
    accumulate order_lines in order
      total: sum order_line.unit_price
      n: count order_line.id
    end
    set order.custom.avg_price to total / n
    
  • Result variables don’t have $ prefix. Inside an accumulate block, you write total: sum ... without the $. They behave like session variables but the syntax in the block header is bare.
Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.