# Building advanced JOLT transformations

JOLT can be used for diverse types of transformations, from basic to advanced. In this document, we explore **advanced operations**, that allow you to:

* Convert objects into lists (and the other way around).
* Insert default values or override existing ones.
* Apply string, numeric, type-conversion, and list functions directly during transformation.

{% hint style="success" %}
**Tip:** Test the examples from this document in the [JOLT playground](https://jolt-demo.appspot.com/#inception).
{% endhint %}

## **Understanding the advanced JOLT operations**

In this section, you’ll learn how each advanced JOLT operation works — `cardinality`, `modify-overwrite-beta`, and `modify-default-beta` — and when to use them.

### **cardinality**

The `cardinality` operation is used to convert a simple object into a list of objects or convert a list back into a single object.

When converting a list into a single object, only the first element of the list is preserved.

#### **Example 1 — Converting an object into a list**

* **Use case:** Standardizing the structure of product data so it always appears as a list, even when only one item is provided.
* **Goal:** Convert the `products` object into an array containing a single element.

**Input JSON**

```json
{
 "products": {
   "name": "Product A",
   "id": "123-A",
   "value": 10
 }
}
```

**Desired output JSON**

```json
{
 "products": [
   {
     "name": "Product A",
     "id": "123-A",
     "value": 10
   }
 ]
}
```

**Transformation spec**

```json
[
 {
   "operation": "cardinality",
   "spec": {
     "products": "MANY"
   }
 }
]
```

**Explanation**

The `cardinality` operation changes how JOLT interprets the structure of a field. By setting `"products": "MANY"`, we tell JOLT that `products` must **always be treated as a list**, even if the input contains just a single object.

JOLT then wraps the existing `products` object inside an array, producing a consistent list structure in the output. This is useful when the payload may sometimes include one item and sometimes many, but the integration requires the field to **always** behave like a list.

#### **Example 2 — Converting a list into a simple object**

* **Use case:** Simplifying product responses by converting lists into a single object when only the first item matters for downstream processing.
* **Goal:** Transform the `products` array into a single object containing only its first element.

**Input JSON**

```json
{
 "products": [
   {
     "name": "Product A",
     "id": "123-A",
     "value": 10
   },
   {
     "name": "Product B",
     "id": "456-B",
     "value": 20
   }
 ]
}
```

**Desired output JSON**

```json
{
 "products": {
   "name": "Product A",
   "id": "123-A",
   "value": 10
 }
}
```

**Transformation spec**

```json
[
 {
   "operation": "cardinality",
   "spec": {
     "products": "ONE"
   }
 }
]
```

**Explanation**

The `cardinality` operation lets you control whether a field should be treated as a **single object** or a **list**. By setting `"products": "ONE"`, we tell JOLT to interpret the `products` field as **a single object**, even when the input provides a list.

JOLT then takes only the **first element** of the array and outputs it as an object. This is useful when you expect a single item but the input may sometimes arrive wrapped in a list.

### **modify-default-beta and modify-overwrite-beta**

These operations allow you to dynamically reference values within the JSON. The difference between them is:

* `modify-default-beta` adds a value only if the field does not already exist.
* `modify-overwrite-beta` always overwrites the field’s value, regardless of whether it exists. Additionally, it supports applying functions to transform values in your JSON.

These functions are grouped into the following categories:

**String functions**

* `toLower`, `toUpper`, `concat`, `join`, `split`, `substring`, `trim`, `leftPad`, `rightPad`

**Number functions**

* `min`, `max`, `abs`, `avg`, `intSum`, `doubleSum`, `longSum`, `intSubtract`, `doubleSubtract`, `longSubtract`, `divide`, `divideAndRound`

**Type functions**

* `toInteger`, `toDouble`, `toLong`, `toBoolean`, `toString`
* `recursivelySquashNulls`, `squashNulls`, `size`

**List functions**

* `firstElement`, `lastElement`, `elementAt`, `toList`, `sort`

#### **Practical example**

* **Use case:** Applying multiple data transformations to enrich and normalize a complex JSON containing strings, numbers, lists, and mixed types.
* **Goal:** Generate a refined output by formatting text, manipulating numeric values, converting data types, removing null fields, extracting list elements, and sorting arrays — all in a single transformation.

**Input JSON**

{% code expandable="true" %}

```json
{
 "STRING": {
   "product": "Product A",
   "company": "company a",
   "value": "100",
   "measureWithSpaces": "  10 meters "
 },
 "NUMBER": {
   "array": [ 3, 5, 2, 7, 1 ],
   "negativeValue": -100,
   "positiveValue": 50
 },
 "TYPE": {
   "value": 10.5,
   "stringBoolean": "true",
   "objectWithNull": {
     "fielWithValue": "ABC",
     "nullField": null
   }
 },
 "LIST": {
   "array": [ "c", "t", "m", "a" ],
   "stringField": "123"
 }
}
```

{% endcode %}

**Desired output JSON**

{% code expandable="true" %}

```json
{
  "STRING" : {
    "product" : "product a",
    "company" : "COMPANY A",
    "value" : "AAA100",
    "measureWithSpaces" : "  10 meters ",
    "product_company" : "product a_COMPANY A",
    "joinProductCompany" : "product a - COMPANY A",
    "splitProductCompany" : [ "product a ", " COMPANY A" ],
    "substringProduct" : "prod",
    "measure" : "10 meters"
  },
  "NUMBER" : {
    "array" : [ 3, 5, 2, 7, 1 ],
    "negativeValue" : -100,
    "positiveValue" : 50,
    "minArray" : 1,
    "maxArray" : 7,
    "absoluteValue" : 100,
    "averageArray" : 3.6,
    "sumArray" : 18,
    "subtrArray" : 30,
    "division" : 25.0,
    "divisionRound" : 16.667
  },
  "TYPE" : {
    "value" : 10.5,
    "stringBoolean" : 4,
    "objectWithNull" : {
      "fielWithValue" : "ABC"
    },
    "integerValue" : 10,
    "booleano" : true,
    "stringValue" : "10.5"
  },
  "LIST" : {
    "array" : [ "c", "t", "m", "a" ],
    "stringField" : "123",
    "arrayFirstItem" : "c",
    "arrayLastItem" : "a",
    "fieldToList" : [ "123" ],
    "orderedArray" : [ "a", "c", "m", "t" ]
  }
}
```

{% endcode %}

**Transformation spec**

{% code expandable="true" %}

```json
[
 {
   "operation": "modify-overwrite-beta",
   "spec": {
     "STRING": {
       "product": "=toLower(@(1,product))",
       "company": "=toUpper(@(1,company))",
       "product_company": "=concat(@(1,product),'_',@(1,company))",
       "joinProductCompany": "=join(' - ',@(1,product),@(1,company))",
       "splitProductCompany": "=split('[-]',@(1,joinProductCompany))",
       "substringProduct": "=substring(@(1,product),0,4)",
       "value": "=leftPad(@(1,value),6,'A')",
       "measure": "=trim(@(1,measureWithSpaces))"
     },
     "NUMBER": {
       "minArray": "=min(@(1,array))",
       "maxArray": "=max(@(1,array))",
       "absoluteValue": "=abs(@(1,negativeValue))",
       "averageArray": "=avg(@(1,array))",
       "sumArray": "=intSum(@(1,array))",
       "subtrArray": "=intSubtract(@(1,positiveValue), 20)",
       "division": "=divide(@(1,positiveValue),2)",
       "divisionRound": "=divideAndRound(3,@(1,positiveValue),3)"
     },
     "TYPE": {
       "integerValue": "=toInteger(@(1,value))",
       "booleano": "=toBoolean(@(1,stringBoolean))",
       "stringValue": "=toString(@(1,value))",
       "stringBoolean": "=size",
       "objectWithNull": "=recursivelySquashNulls"
     },
     "LIST": {
       "arrayFirstItem": "=firstElement(@(1,array))",
       "arrayLastItem": "=lastElement(@(1,array))",
       "arrayElement": "=elementAt(@(1,array),2)",
       "fieldToList": "=toList(@(1,stringField))",
       "orderedArray": "=sort(@(1,array))"
     }
   }
 }
]
```

{% endcode %}

**Explanation**

This example uses the `modify-overwrite-beta` operation to apply **multiple transformations across different data types**, all within a single step. The transformation does the following:

**STRING section**

* Converts string values to **lowercase** and **uppercase**.
* Creates new fields by **concatenating**, **joining**, and **splitting** existing values.
* Extracts substrings using `substring`.
* Pads values with characters using `leftPad`.
* Removes extra spaces with `trim`.

**NUMBER section**

* Calculates **minimum**, **maximum**, **sum**, **subtraction**, **average**, and **absolute values**.
* Performs **division** and **rounded division** with `divideAndRound`.

**TYPE section**

* Converts values to **integer**, **boolean**, and **string**.
* Removes `null` entries inside nested objects using `recursivelySquashNulls`.
* Replaces the `"stringBoolean"` field with its **size**.

**LIST section**

* Extracts the **first**, **last**, and specific array elements.
* Converts a single field into a **list** with `toList`.
* Sorts array values alphabetically using `sort`.

Overall, this transformation demonstrates how `modify-overwrite-beta` can be used to enrich data, clean fields, compute numeric values, normalize types, and organize lists — all within one operation.

#### **Additional notes**

Some functions do not appear in the transformation example because they follow the same usage pattern. For instance, `doubleSum` and `longSum` work exactly like `intSum`.

Regarding null-handling functions:

* **`recursivelySquashNulls`** removes **all** fields with null values at **any** depth.

```json
[
{
    	"operation": "modify-overwrite-beta",
    	"spec": {
      		"*": "=recursivelySquashNulls"
    	}
  }
]
```

* **`squashNulls`** removes null fields only **one level below** the current object or list.

```json
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "product": "=squashNulls"
    }
  }
]
```

#### **Cascading behavior**

The `modify-overwrite-beta` operation applies transformations in the order they appear. This means that each transformation can rely on the values produced by the previous ones — a behavior known as cascading.

The following example demonstrates this clearly.

**Input JSON**

```json
{
  "name": "MARIA",
  "country": "brazil"
}
```

**Transformation spec**

```json
[
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "name": "=toLower",
      "country": "=toLower"
    }
  },
  {
    "operation": "modify-overwrite-beta",
    "spec": {
      "name_country": "=concat(@(1,name),'_',@(1,country))"
    }
  }
]
```

**How it works**

1. **First operation:**\
   Both `name` and `country` are transformed in place.
   * `"MARIA"` becomes `"maria"`
   * `"brazil"` stays `"brazil"`
2. **Second operation:**\
   The transformation creates the `name_country` field by concatenating the **already updated** values of `name` and `country`. Because the first operation has already completed, the function receives the transformed values.

**Result**

```json
{
  "name": "maria",
  "country": "brazil",
  "name_country": "maria_brazil"
}
```

## **Continue learning**

Now that you’ve explored the advanced operations, see how these concepts work in practice by checking out our [**use case examples**](/documentation/resources/use-cases/how-to-jolt/use-cases.md), where each transformation is applied to real integration scenarios.


---

# 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.digibee.com/documentation/resources/use-cases/how-to-jolt/advanced-operations.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.
