# Balanced

The default bundling strategy applies the desired action to the targeted items selecting them in order to ensure a balanced and even distribution across groups (i.e. all groups contribute equally to the single promotional bundles that are recursively identified by the algorithm).

{% hint style="warning" %}
Bundles of type `balanced` can be created starting from at least **two** groups containing at least one item each. If the related `actions.groups` array is made by one group only, the Rule Engine will return an error. If one (or more) of the groups are empty, the action won't be applied.
{% endhint %}

To configure balanced bundles you just need to define the sorting logic within the `sort` object:

<table><thead><tr><th width="137">Key</th><th width="114">Type<select><option value="Djzo1UhBKQfW" label="Boolean" color="blue"></option><option value="VAIMp1rdLBI0" label="Integer" color="blue"></option><option value="qhaoRE82Rs3C" label="Float" color="blue"></option><option value="sk9tHN8WC8KO" label="String" color="blue"></option><option value="B3M67zaVXhvQ" label="Array" color="blue"></option><option value="MFocCrV7v0L6" label="Object" color="blue"></option></select></th><th width="114" data-type="checkbox">Required</th><th width="338">Notes</th></tr></thead><tbody><tr><td><strong><code>type</code></strong></td><td><span data-option="sk9tHN8WC8KO">String</span></td><td>false</td><td>If specified, must be <code>"balanced"</code>.</td></tr><tr><td><strong><code>sort</code></strong></td><td><span data-option="MFocCrV7v0L6">Object</span></td><td>true</td><td>Learn more <a href="/pages/GhfyTAymk4S8RYeOrEeX#sort">here</a>.</td></tr></tbody></table>

## How the `balanced` algorithm works

1. The items within each targeted group are sorted according to the `sort.direction` function applied to the `sort.attribute` numeric field. The groups are also sorted considering the same logic on the same attribute (adding up its value for all the group's items).
2. The total quantity of units within each group is calculated by adding up the quantities of each item.
3. The minimum quantity of units across all group `Q` is the bottleneck of the algorithm (i.e. `Q` is the number of balanced bundles that will be created).
4. Starting from the top of the ordered list generated by the sorting, `Q` elements from each group are picked to be discounted, thus leading to `Q` discountable balanced bundles containing one item per group each.

{% hint style="warning" %}
If some items of the same group match the bundle's `sort.direction` function with the same numeric value of the field specified in the `sort.attribute`, they will be sorted as they are listed in the payload against which the rule is evaluated. If the computation for the total group sorting gives the same result the groups will be sorted in the same order as they are defined in the `actions.groups` array.
{% endhint %}

## Example

Let's assume that a rule's conditions define the following groups of line items:

{% tabs %}
{% tab title="t-shirts" %}
The group labeled as `t-shirts` contains **4** line items for a total of **10** units:

<pre class="language-json"><code class="lang-json">[
  {
    "id": "mnptRLjoXJ",
    "type": "line_items",
<strong>    "quantity": 1,
</strong>    "unit_amount_cents": 10000,
<strong>    "total_amount_cents": 10000,
</strong>    "sku": {
      "id": "zTdkkFXdgN",
<strong>      "code": "TSHIRT01"
</strong>    }
  },
  {
    "id": "jndtDLsoAM",
    "type": "line_items",
<strong>    "quantity": 2,
</strong>    "unit_amount_cents": 5000,
<strong>    "total_amount_cents": 10000,
</strong>    "sku": {
      "id": "xCKdTcQFQH",
<strong>      "code": "TSHIRT02"
</strong>    }
  },
  {
    "id": "AfetSAsqbY",
    "type": "line_items",
<strong>    "quantity": 3,
</strong>    "unit_amount_cents": 3000,
<strong>    "total_amount_cents": 9000,
</strong>    "sku": {
      "id": "meKHSeNbyN",
<strong>      "code": "TSHIRT03"
</strong>    }
  },
  {
    "id": "sjyTdAfrgY",
    "type": "line_items",
<strong>    "quantity": 4,
</strong>    "unit_amount_cents": 2000,
<strong>    "total_amount_cents": 8000,
</strong>    "sku": {
      "id": "uKtHCCJpWn",
<strong>      "code": "TSHIRT04"
</strong>    }
  }
]
</code></pre>

{% endtab %}

{% tab title="polos" %}
The group labeled as `polos` contains **2** line items for a total of **6** units:

<pre class="language-json"><code class="lang-json">[
  {
    "id": "QqRkzFPjIb",
    "type": "line_items",
<strong>    "quantity": 1,
</strong>    "unit_amount_cents": 7000,
    "total_amount_cents": 7000,
    "sku": {
      "id": "cZuCQqLaqd",
<strong>      "code": "POLO01"
</strong>    }
  },
  {
    "id": "PSqqslbiYQ",
    "type": "line_items",
<strong>    "quantity": 5,
</strong>    "unit_amount_cents": 6000,
    "total_amount_cents": 30000,
    "sku": {
      "id": "GjvdHKYIwm",
<strong>      "code": "POLO02"
</strong>    }
  }
]
</code></pre>

{% endtab %}

{% tab title="mugs" %}
The group labeled as `mugs` contains **3** line items for a total of **5** units:

<pre class="language-json"><code class="lang-json">[
  {
    "id": "qOYocnANsO",
    "type": "line_items",
<strong>    "quantity": 3,
</strong>    "unit_amount_cents": 1000,
    "total_amount_cents": 3000,
    "sku": {
      "id": "PeHfayCvwQ",
<strong>      "code": "MUG01"
</strong>    }
  },
  {
    "id": "nlHjpkVpCG",
    "type": "line_items",
<strong>    "quantity": 1,
</strong>    "unit_amount_cents": 4000,
    "total_amount_cents": 4000,
    "sku": {
      "id": "pHaoUAvTVy",
<strong>      "code": "MUG02"
</strong>    }
  },
  {
    "id": "DtZjSMEKvm",
    "type": "line_items",
<strong>    "quantity": 1,
</strong>    "unit_amount_cents": 3000,
    "total_amount_cents": 3000,
    "sku": {
      "id": "TkhHRotCOA",
<strong>      "code": "MUG03"
</strong>    }
  }
]
</code></pre>

{% endtab %}
{% endtabs %}

Let's consider a simple action that uses only the required parameters to be applied to a set of balanced bundles. The following action applies a 20% discount to all the possible bundles that can be created from the groups above, provided that they contain at least one item per group, prioritizing the items with the higher total amount:

<pre class="language-json"><code class="lang-json">"actions": [
  {
    "type": "percentage",
    "selector": "order.line_items.sku",
<strong>    "groups": [ "mugs", "polos", "t-shirts" ],
</strong>    "bundle": {
      "sort": {
<strong>        "attribute": "total_amount_cents",
</strong><strong>        "direction": "desc"
</strong>      }
    },
    "value": 0.2
  }
]
</code></pre>

### 1. Sorting

The items of the group are sorted based on their total amount, from the highest to the lowest. On top of that, the groups are sorted based on the sum of the total amount of each group's item, according to the same logic:

<table><thead><tr><th width="173">SKU</th><th width="139">Group<select><option value="iEX1ezi7BK20" label="t-shirts" color="blue"></option><option value="BtFzpyYa5I66" label="polos" color="blue"></option><option value="FxLP2L81N4FX" label="mugs" color="blue"></option></select></th><th width="106" data-type="number">Quantity</th><th>Item total amount</th><th>Group total amount</th></tr></thead><tbody><tr><td><code>POLO02</code></td><td><span data-option="BtFzpyYa5I66">polos</span></td><td>5</td><td>30000</td><td>37000</td></tr><tr><td><code>POLO01</code></td><td><span data-option="BtFzpyYa5I66">polos</span></td><td>1</td><td>7000</td><td>37000</td></tr><tr><td><code>TSHIRT01</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>1</td><td>10000</td><td>37000</td></tr><tr><td><code>TSHIRT02</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>2</td><td>10000</td><td>37000</td></tr><tr><td><code>TSHIRT03</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>3</td><td>9000</td><td>37000</td></tr><tr><td><code>TSHIRT04</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>4</td><td>8000</td><td>37000</td></tr><tr><td><code>MUG02</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>4000</td><td>10000</td></tr><tr><td><code>MUG01</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>3</td><td>3000</td><td>10000</td></tr><tr><td><code>MUG03</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>3000</td><td>10000</td></tr></tbody></table>

{% hint style="info" %}
`TSHIRT01` ranks higher than `TSHIRT02` within the `t-shirts` group even if they have the same total amount (10000) because this is how they are listed in the payload. The same happens to `MUG01` and `MUG03` within the `mugs` group. The elements of the `polos` groups rank higher than the elements of the `t-shirts` group even if the two groups have the same total amount (37000) because this is how they are listed in the `actions.groups` array.
{% endhint %}

### 2. Total quantity of units

The total quantity of units within each group is:

<table><thead><tr><th>Group<select><option value="iEX1ezi7BK20" label="t-shirts" color="blue"></option><option value="BtFzpyYa5I66" label="polos" color="blue"></option><option value="FxLP2L81N4FX" label="mugs" color="blue"></option></select></th><th data-type="number">Units</th></tr></thead><tbody><tr><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>5</td></tr><tr><td><span data-option="BtFzpyYa5I66">polos</span></td><td>6</td></tr><tr><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>10</td></tr></tbody></table>

### 3. Bottleneck

The group with the lowest total number of units limits the number of bundles that will be created. In this case the `mugs` group is the bottleneck, thus the discount will be applied to **5** bundles.

### 4. Bundles of items to be discounted

We can now pick 5 elements from each group, following the [ordered list](#id-1.-sorting) from top to bottom:

<table><thead><tr><th width="173">SKU</th><th width="139">Group<select><option value="iEX1ezi7BK20" label="t-shirts" color="blue"></option><option value="BtFzpyYa5I66" label="polos" color="blue"></option><option value="FxLP2L81N4FX" label="mugs" color="blue"></option></select></th><th width="106" data-type="number">Quantity</th><th>Discounted total amount</th></tr></thead><tbody><tr><td><code>POLO02</code></td><td><span data-option="BtFzpyYa5I66">polos</span></td><td>5</td><td>24000</td></tr><tr><td><code>TSHIRT01</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>1</td><td>8000</td></tr><tr><td><code>TSHIRT02</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>2</td><td>8000</td></tr><tr><td><code>TSHIRT03</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>2</td><td>4800</td></tr><tr><td><code>MUG02</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>3200</td></tr><tr><td><code>MUG01</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>3</td><td>2400</td></tr><tr><td><code>MUG03</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>2400</td></tr></tbody></table>

This is equivalent to picking one item per group while `mugs` units (our [bottleneck](#id-3.-bottleneck)) last, thus leading to the following 5 bundles to be discounted:

#### Bundle #1

<table><thead><tr><th width="191">SKU</th><th width="156">Group<select><option value="iEX1ezi7BK20" label="t-shirts" color="blue"></option><option value="BtFzpyYa5I66" label="polos" color="blue"></option><option value="FxLP2L81N4FX" label="mugs" color="blue"></option></select></th><th width="136" data-type="number">Quantity</th><th>Discounted unit amount</th></tr></thead><tbody><tr><td><code>POLO02</code></td><td><span data-option="BtFzpyYa5I66">polos</span></td><td>1</td><td>4800</td></tr><tr><td><code>TSHIRT01</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>1</td><td>8000</td></tr><tr><td><code>MUG02</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>3200</td></tr></tbody></table>

#### Bundle #2

<table><thead><tr><th width="191">SKU</th><th width="156">Group<select><option value="iEX1ezi7BK20" label="t-shirts" color="blue"></option><option value="BtFzpyYa5I66" label="polos" color="blue"></option><option value="FxLP2L81N4FX" label="mugs" color="blue"></option></select></th><th width="136" data-type="number">Quantity</th><th>Discounted unit amount</th></tr></thead><tbody><tr><td><code>POLO02</code></td><td><span data-option="BtFzpyYa5I66">polos</span></td><td>1</td><td>4800</td></tr><tr><td><code>TSHIRT02</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>1</td><td>4000</td></tr><tr><td><code>MUG01</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>800</td></tr></tbody></table>

#### Bundle #3

<table><thead><tr><th width="191">SKU</th><th width="156">Group<select><option value="iEX1ezi7BK20" label="t-shirts" color="blue"></option><option value="BtFzpyYa5I66" label="polos" color="blue"></option><option value="FxLP2L81N4FX" label="mugs" color="blue"></option></select></th><th width="136" data-type="number">Quantity</th><th>Discounted unit amount</th></tr></thead><tbody><tr><td><code>POLO02</code></td><td><span data-option="BtFzpyYa5I66">polos</span></td><td>1</td><td>4800</td></tr><tr><td><code>TSHIRT02</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>1</td><td>4000</td></tr><tr><td><code>MUG01</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>800</td></tr></tbody></table>

#### Bundle #4

<table><thead><tr><th width="191">SKU</th><th width="156">Group<select><option value="iEX1ezi7BK20" label="t-shirts" color="blue"></option><option value="BtFzpyYa5I66" label="polos" color="blue"></option><option value="FxLP2L81N4FX" label="mugs" color="blue"></option></select></th><th width="136" data-type="number">Quantity</th><th>Discounted unit amount</th></tr></thead><tbody><tr><td><code>POLO02</code></td><td><span data-option="BtFzpyYa5I66">polos</span></td><td>1</td><td>4800</td></tr><tr><td><code>TSHIRT03</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>1</td><td>2400</td></tr><tr><td><code>MUG01</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>800</td></tr></tbody></table>

#### Bundle #5

<table><thead><tr><th width="191">SKU</th><th width="156">Group<select><option value="iEX1ezi7BK20" label="t-shirts" color="blue"></option><option value="BtFzpyYa5I66" label="polos" color="blue"></option><option value="FxLP2L81N4FX" label="mugs" color="blue"></option></select></th><th width="136" data-type="number">Quantity</th><th>Discounted unit amount</th></tr></thead><tbody><tr><td><code>POLO02</code></td><td><span data-option="BtFzpyYa5I66">polos</span></td><td>1</td><td>4800</td></tr><tr><td><code>TSHIRT03</code></td><td><span data-option="iEX1ezi7BK20">t-shirts</span></td><td>1</td><td>2400</td></tr><tr><td><code>MUG03</code></td><td><span data-option="FxLP2L81N4FX">mugs</span></td><td>1</td><td>2400</td></tr></tbody></table>

### Wrap-up

The results above confirm some general highlights of the balanced bundling strategy:

* An equal contribution of each group to the bundle formation is the distinctive feature. It's a quite strict requirement that leaves some items not discounted (in the analyzed case, 1 unit of `POLO01`, 1 unit of `TSHIRT03`, and 4 units of `TSHIRT04`), prioritizing the ones to discount based on the desired sorting logic.
* Only the elements of the group(s) with the minimum number of total units will be *all* discounted, and the total number of bundles identified will be equal to the number of total units of the group(s) that with minimum number of total units (in the analyzed case, the `mugs` group which has a total number of units equal to 5 and turns out to be the bottleneck of the algorithm).
* The total number of discounted units is given by the number of total units of the group with the minimum number of total units multiplied by the total number of groups (in the analyzed case, `5 * 3 = 15`).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.commercelayer.io/rules-engine/actions/bundle/balanced.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
