# Criando transformações JOLT avançadas

O JOLT pode ser usado para diversos tipos de transformações, das mais básicas às mais avançadas. Neste documento, exploramos **operações avançadas**, que permitem:

* Converter objetos em listas (e vice-versa).
* Inserir valores padrão ou substituir valores existentes.
* Aplicar funções de string, numéricas, de conversão de tipo e de listas diretamente durante a transformação.

{% hint style="success" %}
**Dica:** Teste os exemplos deste documento no [playground do JOLT](https://jolt-demo.appspot.com/#inception).
{% endhint %}

## **Entendendo as operações avançadas do JOLT**

Nesta seção, você aprenderá como cada operação avançada do JOLT funciona — `cardinality`, `modify-overwrite-beta` e `modify-default-beta` — e quando usá-las.

### **cardinality**

A operação `cardinality` é usada para converter um objeto simples em uma lista de objetos ou transformar uma lista de volta em um único objeto.

Ao converter uma lista em um objeto único, apenas o primeiro elemento da lista é preservado.

#### **Exemplo 1 — Convertendo um objeto em uma lista**

* **Caso de uso:** Padronizar a estrutura dos dados de produto para que eles sempre apareçam como uma lista, mesmo quando apenas um item é fornecido.
* **Objetivo:** Converter o objeto `products` em um array contendo um único elemento.

**JSON de entrada**

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

**JSON de saída desejado**

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

**Spec de transformação**

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

**Explicação**

A operação `cardinality` altera como o JOLT interpreta a estrutura de um campo. Ao definir `"products": "MANY"`, indicamos ao JOLT que `products` deve **sempre ser tratado como uma lista**, mesmo que a entrada contenha apenas um único objeto.

O JOLT então envolve o objeto `products` existente dentro de um array, produzindo uma estrutura de lista consistente na saída. Isso é útil quando o payload às vezes inclui um item e às vezes muitos, mas a integração exige que o campo **sempre** se comporte como uma lista.

#### **Exemplo 2 — Convertendo uma lista em um objeto simples**

* **Caso de uso:** Simplificar respostas de produto convertendo listas em um único objeto quando apenas o primeiro item é relevante para o processamento posterior.
* **Objetivo:** Transformar o array `products` em um único objeto contendo apenas seu primeiro elemento.

**JSON de entrada**

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

**JSON de saída desejado**

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

**Spec de transformação**

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

**Explicação**

A operação `cardinality` permite controlar se um campo deve ser tratado como um **objeto único** ou uma **lista**. Ao definir `"products": "ONE"`, informamos ao JOLT que o campo `products` deve ser interpretado como **um único objeto**, mesmo quando a entrada fornece uma lista.

O JOLT então pega apenas o **primeiro elemento** do array e o retorna como um objeto. Isso é útil quando você espera apenas um item, mas a entrada pode, às vezes, chegar dentro de uma lista.

### **modify-default-beta e modify-overwrite-beta**

Essas operações permitem referenciar valores de forma dinâmica dentro do JSON. A diferença entre elas é:

* `modify-default-beta` adiciona um valor somente se o campo ainda não existir.
* `modify-overwrite-beta` sempre substitui o valor do campo, independentemente de ele existir. Além disso, ela permite aplicar funções para transformar valores no JSON.

Essas funções são agrupadas nas seguintes categorias:

**Funções de string**

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

**Funções numéricas**

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

**Funções de tipo**

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

**Funções para listas**

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

#### **Exemplo prático**

* **Caso de uso:** Aplicar múltiplas transformações para enriquecer e normalizar um JSON complexo contendo strings, números, listas e tipos mistos.
* **Objetivo:** Gerar uma saída refinada formatando textos, manipulando valores numéricos, convertendo tipos, removendo campos nulos, extraindo elementos de listas e ordenando arrays — tudo em uma única transformação.

**JSON de entrada**

{% 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 %}

**JSON de saída desejado**

{% 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 %}

**Spec de transformação**

{% 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 %}

**Explicação**

Este exemplo usa a operação `modify-overwrite-beta` para aplicar **múltiplas transformações em diferentes tipos de dados**, tudo em uma única etapa. A transformação faz o seguinte:

**Seção STRING**

* Converte valores de string para **letras minúsculas** e **maiúsculas**.
* Cria novos campos por meio de **concatenação**, **junção (join)** e **separação (split)** de valores existentes.
* Extrai substrings usando `substring`.
* Preenche valores com caracteres usando `leftPad`.
* Remove espaços extras com `trim`.

**Seção NUMBER**

* Calcula **mínimo**, **máximo**, **soma**, **subtração**, **média** e **valor absoluto**.
* Realiza **divisão** e **divisão arredondada** com `divideAndRound`.

**Seção TYPE**

* Converte valores para **integer**, **boolean** e **string**.
* Remove campos `null` dentro de objetos aninhados usando `recursivelySquashNulls`.
* Substitui o campo `"stringBoolean"` pelo seu **tamanho**.

**Seção LIST**

* Extrai o **primeiro**, **último** e elementos específicos de um array.
* Converte um único campo em uma **lista** usando `toList`.
* Ordena valores de array alfabeticamente com `sort`.

No geral, esta transformação demonstra como `modify-overwrite-beta` pode ser usada para enriquecer dados, limpar campos, calcular valores numéricos, normalizar tipos e organizar listas — tudo em uma única operação.

#### **Notas adicionais**

Algumas funções não aparecem no exemplo de transformação porque seguem o mesmo padrão de uso. Por exemplo, `doubleSum` e `longSum` funcionam exatamente como `intSum`.

Sobre as funções de tratamento de nulos:

* **`recursivelySquashNulls`** remove **todos** os campos com valores nulos em **qualquer** nível de profundidade.

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

* **`squashNulls`** remove campos nulos apenas **um nível abaixo** do objeto ou lista atual.

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

#### **Comportamento em cascata**

A operação `modify-overwrite-beta` aplica as transformações na ordem em que aparecem. Isso significa que cada transformação pode utilizar os valores produzidos pelas anteriores — um comportamento conhecido como **cascata**.

O exemplo a seguir demonstra isso de forma clara.

**JSON de entrada**

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

**Spec de transformação**

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

**Como funciona**

1. **Primeira operação:**\
   Tanto `name` quanto `country` são transformados no próprio campo.
   * `"MARIA"` se torna `"maria"`
   * `"brazil"` permanece `"brazil"`
2. **Segunda operação:**\
   A transformação cria o campo `name_country` concatenando os valores **já atualizados** de `name` e `country`. Como a primeira operação já foi concluída, a função recebe os valores transformados.

**Resultado**

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

## **Continue aprendendo**

Agora que você explorou as operações avançadas, veja como esses conceitos funcionam na prática acessando nossos [**exemplos de casos de uso**](/documentation/resources/pt-br/use-cases/how-to-jolt/use-cases.md), onde cada transformação é aplicada a cenários reais de integração.


---

# 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/pt-br/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.
