---
source: https://carbone.io/documentation/design/computation/store-and-transform.html
title: "Store, modify, and transform JSON to simplify your templates"
description: "Store, modify, and transform JSON to simplify your templates"
generated_at: "2026-07-10"
---

# Store and transform

Store, modify, and transform JSON to simplify your templates  
ENTERPRISE FEATURE Available for:  
✓ Carbone Cloud  
✓ Carbone On-premise  
✗ Embedded Carbone JS   v5.0+ 

> ℹ️ **Note:** This feature is officially available in Carbone v5. However, you can activate it in v4 by inserting `{o.preReleaseFeatureIn=4022011}` into your template.  
> For more details, refer to the [Files and features documentation](/documentation/design/overview/version-lifecycle.md#pre-release-features).

## Store values -> :set(absolutePath)

The `:set(absolutePath)` formatter allows you to store values in data. [absolutePath](/documentation/design/formatters/overview.md#dynamic-parameters) specifies the destination where the value will be stored.

-   It is good practice to store new variables in the **complement object** (`{c.}`) instead of the **data object** (`{d.}`). This helps maintain a cleaner and more organized data structure.
-   The execution order of multiple Carbone tags using the `:set` formatter is guaranteed within the same section of a document (e.g., body, header, footer, or text box).  
    As a result, you can create new variables that depend on previously created ones. When one `:set` expression is used to create another, the new expression must be defined after or below the existing one.
-   The `:set` formatter overwrites existing values in the data.
-   Only alphanumeric characters are allowed for newly created JSON attributes, objects, or arrays (no spaces or special characters such as commas, parentheses, etc.).

> ℹ️ **Note:** A Carbone tag using `:set` does not print anything in the generated report. The tag is removed when executed. A loop with iterators `[i]` cannot be used in combination with `:set`.

**Example: store the sum in c.mySum**

```cdata
{
  "cars": [
    { "qty" : 1 },
    { "qty" : 4 }
  ]
}
```

```ctemplate
{d.cars[].qty:aggSum:set(c.mySum)}
Print stored value: {c.mySum}
```

```cresult
Print stored value: 5
```

**Example with order of execution:**

```cdata
{
  "price" : 1
}
```

```ctemplate
{d.price:add(10):set(d.total1)}
{d.total1:add(20):set(d.total2)}
Result: {d.total2}
```

```cresult
Result: 31
```

## Modify JSON -> :set(.relativePath)

Add or modify attributes in your data using a [JSON relative path](/documentation/design/formatters/overview.md#dynamic-parameters).

In this example, the Carbone tag `{d.cars[].qty:append(' tyres'):set(.newInfo)}` adds the attribute "newInfo" to all objects in the "cars" array.

-   `d.cars[]`: Loops over all cars.
-   `.qty`: Prints the `qty` value.
-   `append(' tyres')`: Appends the string " tyres" to `qty`.
-   `:set(.newInfo)`: Stores the result in the new attribute `newInfo` in each object of `cars`

```cdata
{
  "cars": [
    { "qty" : 1 },
    { "qty" : 4 }
  ]
}
```

```ctemplate
{d.cars[].qty:append(' tyres'):set(.newInfo)}
### JSON Modified
{d:printJSON}
### JSON Usage
- {d.cars[i].newInfo}
- {d.cars[i+1].newInfo}
```

```cresult
### JSON Modified
{
  "cars": [
    {"qty": 1, "newInfo": "1 tyres"},
    {"qty": 4, "newInfo": "4 tyres"}
  ]
}
### JSON Usage
- 1 tyres
- 4 tyres
```

## Transform JSON -> :set(absolutePath\[\])

Generate a completely new JSON structure with the `:set` formatter.

Here is an overview of the syntax:

`{ d.sourceArray[arrayFilter] :set( c.destinationArray[searchExpression] )}`

-   `d.sourceArray` : The existing array
-   `[arrayFilter]` : Optional array filters. The `i` iterator is not allowed with the `:set` formatter. Leave empty `[]` to traverse all data.
-   `:set`: The formatter
-   `c.destinationArray` : The newly created array in `c.`. Only alphanumeric characters are allowed for newly created JSON attributes, objects, or arrays.
-   `[searchExpression]` : An optional condition used to find and merge items with existing ones in the newly created array. It works like an inner join expression in SQL. An empty `searchExpression` is accepted only for the last created array in the `:set()` expression. In this case, all items are aggregated without searching for existing ones. Only the equality `=` operator is allowed in the `searchExpression`, and exactly one expression is permitted within `[]`. This `searchExpression` works only on newly created arrays by Carbone, not on existing arrays in the original JSON data passed when calling Carbone.

**Learn the basics with simple examples:**

-   [Clone arrays](#transform-json-set-absolutepath-cloning-arrays)
-   [Selective array cloning](#transform-json-set-absolutepath-selective-array-cloning)
-   [Merge arrays](#transform-json-set-absolutepath-merge-arrays)

**Advanced usage with search/join expressions:**

-   [Distinct merge](#transform-json-set-absolutepath-distinct-merge)
-   [Group data in nested arrays](#transform-json-set-absolutepath-group-data-in-nested-arrays)

### Cloning arrays

`{ d.myArray[] :set( c.new[] )}`

-   `d.myArray[]` : Loops over the existing array and retrieves its content
-   `:set(c.new[])`: Injects the content into a new array located at `{c.new}`.

**Array of objects example:**

```cdata
{
  "myArray" : [
    { "country" : "A", "city" : "1A" },
    { "country" : "A", "city" : "2A" },
    { "country" : "B", "city" : "1B" }
  ]
}
```

```ctemplate
{d.myArray[]:set(c.new[])}
### JSON Generated
{c:printJSON}
```

```cresult
### JSON Generated
{
  "new": [
    {"country": "A", "city": "1A"},
    {"country": "A", "city": "2A"},
    {"country": "B", "city": "1B"}
  ]
}
```

**Array of strings example:**

```cdata
{
  "myArray" : [ "A", "B", "C"]
}
```

```ctemplate
{d.myArray[]:set(c.new[])}
### JSON Generated
{c:printJSON}
```

```cresult
### JSON Generated
{"new": ["A", "B", "C"]}
```

### Selective array cloning

In this example, only the `country` attribute is injected into the new array.

As you can see, Carbone creates an array of strings or an array of objects according to destination `c.newArr1[]` or `c.newArr2[].country`.

```cdata
{
  "myArray" : [
    { "country" : "A", "city" : "1A" },
    { "country" : "A", "city" : "2A" },
    { "country" : "B", "city" : "1B" }
  ]
}
```

```ctemplate
{d.myArray[].country:set(c.newArr1[])}
{d.myArray[].country:set(c.newArr2[].country)}
### JSON Generated
{c:printJSON}
```

```cresult
### JSON Generated
{
  "newArr1": ["A", "A", "B"],
  "newArr2": [
    {"country": "A"},
    {"country": "A"},
    {"country": "B"}
  ]
}
```

### Merge arrays

```cdata
{
  "myArray" : [
    { "country" : "A", "city" : "1A" },
    { "country" : "A", "city" : "2A" },
    { "country" : "B", "city" : "1B" }
  ],
  "myArray2" : [
    { "country" : "C", "city" : "1C" },
    { "country" : "A", "city" : "3A" }
  ]
}
```

```ctemplate
{d.myArray[]:set(c.newArr[])}
{d.myArray2[]:set(c.newArr[])}
### JSON Generated
{c:printJSON}
```

```cresult
JSON Generated{
  "newArr": [
    {"country": "A", "city": "1A"},
    {"country": "A", "city": "2A"},
    {"country": "B", "city": "1B"},
    {"country": "C", "city": "1C"},
    {"country": "A", "city": "3A"}
  ]
}
```

### Distinct Merge

Carbone accepts a **search expression** enclosed in square brackets to determine how to add new items.

If an item in the new array **matches the condition**, the **new item is merged** with the **existing one**

`{ d.myArray[] :set( c.new[ country = .country] )}`

-   `d.myArray[]` : Loops over the existing array and returns its content
-   `:set(c.new[ country = .country ])`: Injects the content into a new array
    -   `c.new` is the newly created array in `c.`
    -   `[country=.country]` is a search expression used to find existing items that match the criteria
    -   `country` is a relative path to the new object inside `c.new`. Equivalent to `c.new[].country`
    -   `.country` is a relative path in the currently visited array. Equivalent to `d.myArray[].country`

```cdata
{
  "myArray" : [
    { "country" : "A", "city" : "1A" },
    { "country" : "A", "city" : "2A" },
    { "country" : "B", "city" : "1B" }
  ],
  "myArray2" : [
    { "country" : "C", "city" : "1C" },
    { "country" : "A", "city" : "3A" }
  ]
}
```

```ctemplate
{d.myArray[]:set(c.new[country=.country])}
{d.myArray2[]:set(c.new[country=.country])}
### JSON Generated
{c:printJSON}
```

```cresult
JSON Generated{
  "new": [
    {"country": "A", "city": "3A"},
    {"country": "B", "city": "1B"},
    {"country": "C", "city": "1C"}
  ]
}
```

**Automatic creation of non-existing attributes**

If the left operand of the condition does not exist, Carbone automatically creates it (`c.new[].id`).

```cdata
{
  "myArray" : [
    { "country" : "A" },
    { "country" : "A" },
    { "country" : "B" }
  ],
  "myArray2" : [
    { "country" : "C" },
    { "country" : "A" }
  ]
}
```

```ctemplate
{d.myArray[]:set(c.new[id=.country])}
{d.myArray2[]:set(c.new[id=.country])}
### JSON Generated
{c:printJSON}
```

```cresult
JSON Generated{
  "new": [
    {"country": "A", "id": "A"},
    {"country": "B", "id": "B"},
    {"country": "C", "id": "C"}
  ]
}
```

### Group data in nested arrays

Carbone accepts a **search expression** enclosed in square brackets to determine how to add new items.

If an item in the new array **matches the condition**, the **new item is merged** with the **existing one**

`{ d.myArray[] :set( c.countries[ id = .country].cities[] )}`

-   `d.myArray[]` : Loops over the existing array and returns its content
-   `:set(c.countries[ id = .country ]`: Injects the content into the new array `c.countries[]`
    -   `c.countries` is the newly created array in `c.`
    -   `[id=.country]` is a search expression used to find existing items that match the criteria
    -   `id` is a relative path to the new object inside `c.countries`. Equivalent to `c.countries[].id`
    -   `.country` is a relative path within the currently visited array. Equivalent to `d.myArray[].country`
-   `.cities[])`: For each country, injects items into the new nested array `cities[]`

```cdata
{
  "myArray" : [
    { "country" : "A", "city" : "1A" },
    { "country" : "A", "city" : "2A" },
    { "country" : "B", "city" : "1B" },
    { "country" : "B", "city" : "2B" },
    { "country" : "A", "city" : "3A" }
  ]
}
```

```ctemplate
{d.myArray[]:set(c.countries[id=.country].cities[])}
### JSON Generated
{c:printJSON}
```

```cresult
### JSON Generated
{
  "countries": [
    {
      "id": "A",
      "cities": [
        {"country": "A", "city": "1A"},
        {"country": "A", "city": "2A"},
        {"country": "A", "city": "3A"}
      ]
    },
    {
      "id": "B",
      "cities": [
        {"country": "B", "city": "1B"},
        {"country": "B", "city": "2B"}
      ]
    }
  ]
}
```

**Other examples**

Here, only `city` is injected into the `:set`. Carbone creates an array of strings.

```cdata
{
  "myArray" : [
    { "country" : "A", "city" : "1A" },
    { "country" : "A", "city" : "2A" },
    { "country" : "B", "city" : "1B" },
    { "country" : "B", "city" : "2B" },
    { "country" : "B", "city" : "3B" },
    { "country" : "A", "city" : "3A" }
  ]
}
```

```ctemplate
{d.myArray[].city:set(c.countries[title=.country].cities[])}
### JSON Generated
{c:printJSON}
```

```cresult
### JSON Generated
{
  "countries": [
    {
      "title": "A",
      "cities": ["1A", "2A", "3A"]
    },
    {
      "title": "B",
      "cities": ["1B", "2B", "3B"]
    }
  ]
}
```

## Join two arrays -> :set(absolutePath\[\])

Here is a basic example to join two separate arrays:

```cdata
{
  "actors": [
    { "id" : 10, "firstName" : "Keanu"  },
    { "id" : 20, "firstName" : "Margot" }
  ],
  "movies": [
    { "actorId" : 10, "name" : "Matrix"    },
    { "actorId" : 20, "name" : "Babylon"   },
    { "actorId" : 10, "name" : "John Wick" }
  ]
}
```

```ctemplate
{d.actors[]:set(c.actors[id=.id])}
{d.movies[]:set(c.actors[id=.actorId].movies[])}
## JSON Generated
{c.actors:printJSON}
```

```cresult
JSON Generated[
  {
    "id": 10,
    "firstName": "Keanu",
    "movies": [
      {"actorId": 10, "name": "Matrix"},
      {"actorId": 10, "name": "John Wick"}
    ]
  },
  {
    "id": 20,
    "firstName": "Margot",
    "movies": [
      {"actorId": 20, "name": "Babylon"}
    ]
  }
]
```

Get inspired by one of our real-life examples: [Gallery of images](/examples/gallery-simple/index.md), [Bank Statement](/examples/bank-statement-expert/index.md) or [Planning with subtotals](/examples/planification-medium/index.md)

## Related topics

- [Simple Mathematics](/documentation/design/computation/simple-mathematics.md)
- [Aggregators](/documentation/design/computation/aggregation.md)
