> For the complete documentation index, see [llms.txt](https://docs.datajet-app.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.datajet-app.com/liquid/filters/group_by_exp.md).

# group\_by\_exp

Groups an array using a Liquid expression to determine the group key. Unlike `group_by`, which groups by a direct property value, `group_by_exp` lets you write arbitrary expressions to compute the grouping key.

```liquid
{% assign by_price_range = products | group_by_exp: "product", "product.price > 100" %}
{% for group in by_price_range %}
  {% log group.name | append: ": " | append: group.items.size | append: " products" %}
{% endfor %}
```

#### Syntax

```liquid
{{ array | group_by_exp: item_name, expression }}
```

| Parameter    | Description                                              |
| ------------ | -------------------------------------------------------- |
| `array`      | Array of objects to group                                |
| `item_name`  | Variable name for the current item inside the expression |
| `expression` | Liquid expression that produces the group key            |

#### Return Value

Returns an array of group objects:

| Property | Type  | Description                                              |
| -------- | ----- | -------------------------------------------------------- |
| `name`   | any   | The computed key value shared by all items in this group |
| `items`  | Array | Array of items that produced this key value              |

#### Examples

**Group products by price range:**

```liquid
{% assign by_range = products | group_by_exp: "p", "p.price > 50" %}
{% for group in by_range %}
  {% if group.name == true %}
    {% log "Premium products: " | append: group.items.size %}
  {% else %}
    {% log "Budget products: " | append: group.items.size %}
  {% endif %}
{% endfor %}
```

**Group by first letter of title:**

```liquid
{% assign by_letter = products | group_by_exp: "p", "p.title | slice: 0" %}
{% for group in by_letter %}
  {% log group.name | append: ": " | append: group.items.size | append: " products" %}
{% endfor %}
```

**Group orders by fulfillment state:**

```liquid
{% assign by_state = orders | group_by_exp: "o", "o.fulfillment_status | default: 'unfulfilled'" %}
{% for group in by_state %}
  {% log group.name | append: ": " | append: group.items.size %}
{% endfor %}
```

**Group by computed value using filters:**

```liquid
{% assign by_month = orders | group_by_exp: "o", "o.created_at | date: '%Y-%m'" %}
{% for group in by_month %}
  {% log group.name | append: ": " | append: group.items.size | append: " orders" %}
{% endfor %}
```

Output:

```
2025-01: 156 orders
2025-02: 203 orders
2025-03: 178 orders
```

**Group line items by quantity tier:**

```liquid
{% assign by_tier = line_items | group_by_exp: "item", "item.quantity > 10" %}
{% for group in by_tier %}
  {% if group.name == true %}
    {% log "Bulk orders: " | append: group.items.size %}
  {% else %}
    {% log "Regular orders: " | append: group.items.size %}
  {% endif %}
{% endfor %}
```

#### Notes

* The `item_name` parameter defines how you reference each item inside the expression
* The expression can use any Liquid filters and operators
* The expression result becomes the group `name` — it can be a string, number, boolean, etc.
* Groups are returned in the order their keys are first encountered
* For simple property-based grouping, `group_by` is more concise
* See also: `group_by`, `group_by_property`, `group_by_fast`
