# Entendendo os operadores JOLT (wildcards)

Os operadores do JOLT, também conhecidos como **wildcards**, são um dos recursos mais poderosos do framework. Eles permitem manipular valores, capturar nomes de campos, lidar com entradas opcionais e criar estruturas flexíveis mesmo quando o formato de entrada varia.

Neste guia, você verá como cada operador funciona, que tipo de problema ele resolve e como usá-lo para simplificar cenários de transformação básicos e avançados.

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

## **Conceitos importantes**

Até agora, cobrimos os conceitos essenciais do JOLT. Antes de avançar para as operações avançadas, precisamos apresentar dois elementos fundamentais usados em todas as especificações JOLT: **LHS** e **RHS**.

### **LHS e RHS**

Toda operação JOLT é construída em torno de dois lados:

* **LHS (Left Hand Side):** A parte antes dos dois-pontos (`:`), onde **selecionamos** ou **casamos** campos da entrada.
* **RHS (Right Hand Side):** A parte depois dos dois-pontos (`:`), onde **atribuímos** ou **mapeamos** valores para a saída.

Os operadores se comportam de maneiras diferentes no **LHS** e no **RHS**, e entender essa distinção é essencial para criar regras de transformação poderosas e flexíveis.

Exemplo:

```json
[
 {
   "operation": "shift",
   "spec": {
LHS -> "customer": {
 LHS ->  "name": "client.fullName",  <- RHS
 LHS ->  "birhtDate": "client.dateOfBirth",  <- RHS
 LHS ->  "address": "client.address.street",  <- RHS
 LHS ->  "country": "client.address.country"  <- RHS
     }
   }
 }
}
```

## **Análise detalhada dos operadores**

Vamos analisar cada operador e observar como ele se comporta em transformações reais. Nas próximas seções, você encontrará explicações e exemplos que mostram exatamente como cada operador funciona e qual tipo de saída produz.

### **& (“e” comercial)**

Usa o **nome do campo encontrado no LHS** para construir a estrutura no JSON de saída, sem exigir que você defina o nome manualmente no RHS.

* **Uso:** RHS
* **Operação:** `shift`

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

* **Caso de uso:** Agrupar campos relacionados de um cliente em um único objeto.
* **Objetivo:** Mover os campos existentes para um novo objeto `client` sem renomeá-los.

**JSON de entrada**

```json
{
 "name": "Client Example",
 "email": "client-example@email.com"
}
```

**JSON de saída desejado**

```json
{
 "client": {
   "name": "Client Example",
   "email": "client-example@email.com"
 }
}
```

**Spec de transformação**

```json
[
 {
   "operation": "shift",
   "spec": {
     "name": "client.&",
     "email": "client.&"
   }
 }
]
```

**Explicação**

Essa transformação move os campos originais `name` e `email` para dentro de um novo objeto `client`.

O wildcard `&` mantém **o mesmo nome de campo** do input ao criar a estrutura de saída.

* `"name": "client.&"` pega o valor de `name` e o coloca em `client.name`.
* `"email": "client.&"` faz o mesmo para `email`, gerando `client.email`.

Ao usar `&`, você não precisa repetir manualmente cada nome de campo no RHS. O JOLT preserva automaticamente o nome original enquanto organiza os campos dentro de `client`.

### **\* (asterisco)**

Refere-se a **todos os campos ou objetos**, sem precisar listar cada um explicitamente.

* **Uso:** LHS
* **Operações:** `shift`, `remove`, `cardinality`, `modify-default-beta`, `modify-overwrite-beta`

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

* **Caso de uso:** Organizar os dados de um cliente agrupando todos os campos sob um único objeto pai.
* **Objetivo:** Aninhar todos os campos dentro de um objeto `customer` e renomear `document` para `ssn`.

**JSON de entrada**

```json
{
 "name": "Customer Example",
 "email": "cliente-exemplo@email.com",
 "document": "1234567890",
 "birthDate": "10/31/1990",
 "address": "Customer Example Street"
}
```

**JSON de saída desejado**

```json
{
 "customer": {
   "name": "Customer Example",
   "email": "client-example@email.com",
   "document": "1234567890",
   "birthDate": "10/31/1990",
   "address": "Customer Example Street"
 }
}
```

**Spec de transformação**

```json
[
 {
   "operation": "shift",
   "spec": {
     "*": "customer.&",
     "document": "customer.ssn"
   }
 }
]
```

**Explicação**

Na linha `"*": "customer.&"`, pegamos **qualquer campo encontrado no JSON de entrada** e o colocamos dentro de um novo objeto **customer**, preservando tanto o nome do campo quanto toda a sua estrutura.

Para o campo `document`, pegamos seu valor e o mapeamos para um novo campo chamado `ssn`, também dentro do objeto `customer`.

**Como funciona:**

* `*` corresponde a **qualquer campo**.
* `&` mantém o **nome e o valor originais** do campo.
* Quando usados juntos (`*` + `&`), o JOLT copia automaticamente todos os campos correspondentes **sem que você precise especificá-los um por um**.

Essa combinação é útil quando você precisa **manipular ou reorganizar um JSON** sem conhecer toda a sua estrutura com antecedência.

### **@ (arroba)**

Faz referência ao **valor** de um campo.

Seu comportamento muda dependendo da operação e de estar no LHS ou RHS.

* **Uso:** LHS e RHS
* **Operações:** `shift`, `modify-default-beta`, `modify-overwrite-beta`

#### **Exemplo com `shift`**

* **Caso de uso:** Criar nomes de campos dinamicamente com base nos valores de entrada.
* **Objetivo:** Usar o valor de `key` para definir o nome do campo dentro de `product`, atribuindo a ele o valor de `value`.

**JSON de entrada**

```json
{  
   "key": "code",  
   "value": "123-ABC"
}
```

**JSON de saída desejado**

```json
{  
   "product": {    
       "code": "123-ABC"  
   }
}
```

**Spec de transformação**

```json
[
 {
   "operation": "shift",
   "spec": {
     "value": "product.@(1,key)"
   }
 }
]
```

**Explicação**

Em `product.@(1,key)`, a expressão `@(1,key)` diz ao JOLT para:

* Subir **um nível** (por causa do `1`),
* Encontrar o campo chamado **`key`**,
* Usar seu **valor (`"code"`) como nome do novo campo** dentro de `product`.

Isso significa que o valor de `"value"` (`"123-ABC"`) é atribuído a um campo com nome dinâmico (`"code"`).

**Como o @ funciona:**

* `@` faz referência a dados de outra parte do JSON.
* O primeiro argumento (`1`) indica **quantos níveis acima** procurar.
* O segundo argumento (`key`) indica **qual valor de campo recuperar**.
* A mesma lógica se aplica quando `@` é usado no LHS ou RHS do spec.

Esse mecanismo permite **criar nomes de campo dinamicamente** com base em valores do JSON de entrada, proporcionando transformações mais flexíveis.

#### **Exemplos de `modify-default-beta` e `modify-overwrite-beta`**

* **Caso de uso:** Enriquecer um objeto aninhado com informações armazenadas em outra parte do JSON.
* **Objetivo:** Adicionar um campo `company` dentro de `product`, usando o valor do campo de nível superior `manufacturer`.

**JSON de entrada**

```json
{
 "product": {
   "name": "Produto A",
   "price": 10
 },
 "manufacturer": "Company A"
}
```

**JSON de saída desejado**

```json
{
 "product": {
   "name": "Product A",
   "price": 10,
   "company": "Company A"
 },
 "manufacturer": "Company A"
}
```

**Spec de transformação**

```json
[
 {
   "operation": "modify-default-beta",  //para modify-overwrite-beta 
   "spec": {                            //nós teríamos a mesma transformação
     "produto": {                       <- nível 2   
       "company": "@(2,manufacturer)"   <- nível 1 
     }
   }
 }
]
```

**Explicação**

Criamos um novo campo chamado **`company`** dentro do objeto `product` e atribuímos a ele o valor do campo **`manufacturer`**.

Para isso, usamos `@(2,manufacturer)`, que instrui o JOLT a:

* Subir **dois níveis** (a partir de dentro de `product`),
* Encontrar o campo chamado **`manufacturer`**,\
  Recuperar **seu valor e atribuí-lo a `product.company`**.

**`modify-default-beta` vs. `modify-overwrite-beta`**

* **`modify-default-beta`:** Adiciona o campo `company` **somente se ele ainda não existir** dentro de `product`. Ele preserva valores existentes.
* **`modify-overwrite-beta`:** Adiciona o campo `company` **mesmo que ele já exista**, sempre substituindo o valor existente. Como o nome sugere, ele **sobrescreve** qualquer conteúdo anterior.

Ambas as operações usam o mesmo spec de transformação. A única diferença é o comportamento em relação à sobrescrita.

### **$ (cifrão)**

Faz referência **ao nome de um campo**, em vez de seu valor.

* **Uso:** LHS
* **Operação:** `shift`

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

* **Caso de uso:** Identificar quais campos existem dentro de um objeto `product`.
* **Objetivo:** Gerar uma lista com os nomes de todos os campos dentro de `product`.

**JSON de entrada**

```json
{
 "product": {
   "name": "Product Example",
   "value": 10,
   "category": "CATEG-1",
   "weight": 25
 }
}
```

**JSON de saída desejado**

```json
{
 "product": [
   "name",
   "value",
   "category",
   "weight"
 ]
}
```

**Spec de transformação**

```json
[
 {
   "operation": "shift",
   "spec": {
     "product": {
       "*": {
         "$": "product[]"
       }
     }
   }
 }
]
```

**Explicação**

Selecionamos todos os campos (`*`) dentro do objeto `product` e usamos `$` para recuperar **o nome de cada campo**, não o seu valor. Em seguida, colocamos cada nome recuperado dentro da lista `product[]`.

Isso permite gerar uma estrutura que captura **apenas os nomes dos campos** do JSON de entrada.

### **# (cerquilha)**

O operador `#` possui funções diferentes dependendo de onde é usado:

* **Uso:**
  * **LHS:** Permite inserir **valores manuais (constantes)** no JSON de saída.
  * **RHS:** Usado **exclusivamente para criar listas**, agrupando conteúdo de níveis superiores em uma nova estrutura de lista.
* **Operação:** `shift`

#### **Exemplo no LHS**

* **Caso de uso:** Adicionar um campo ausente que não é fornecido no JSON de entrada.
* **Objetivo:** Inserir um campo padrão `category` dentro de `product`, preservando todos os campos existentes.

**JSON de entrada**

```json
{ 
 "product": { 
   "name": "Product Example", 
   "value": 10, 
   "weight": 25 
 } 
}
```

**JSON de saída desejado**

```json
{
  "product" : {
    "category" : "DEFAULT-CATEGORY",
    "name" : "Product Example",
    "value" : 10,
    "weight" : 25
  }
}
```

**Spec de transformação**

```json
[
 {
   "operation": "shift",
   "spec": {
     "product": {
       "*": "product.&",
       "#DEFAULT-CATEGORY": "product.category"
     }
   }
 }
]
```

**Explicação**

O valor após o curinga `#` (**`DEFAULT-CATEGORY`**) é **inserido manualmente** no campo especificado no RHS (`product.category`).

Isso garante que o campo seja sempre incluído, independentemente da entrada.

#### **Exemplo no RHS**

* **Caso de uso:** Padronizar nomes de campos dentro de uma lista de objetos `products`.
* **Objetivo:** Renomear o campo `value` para `price` em cada item do array `products`.

**JSON de entrada**

```json
{
 "products": [
   {
     "code": "PROD-A",
     "value": 10
   },
   {
     "code": "PROD-B",
     "value": 20
   }
 ]
}
```

**JSON de saída desejado**

```json
{  
 "products": [
   {
     "code": "PROD-A",
     "price": 10
   },
   {
     "code": "PROD-B",
     "price": 20
   }
 ]
}
```

**Spec de transformação**

```json
[
  {
    "operation": "shift",
    "spec": {
      "products": {                      // level 2
        "*": {                           // level 1
          "code": "products[#2].&",      // level 0
          "value": "products[#2].price"  // level 0
        }
      }
    }
  }
]
```

**Explicação**

Usar `#` no RHS significa:

* Estamos **criando uma lista** (`[...]`).
* `#2` indica ao JOLT que deve agrupar os elementos com base na estrutura encontrada **dois níveis acima**.
* Isso garante que cada `code` e seu respectivo `price` permaneçam juntos dentro do mesmo objeto `product`.

Portanto:

* `"code": "products[#2].&"`: Pega o valor de `code` e o coloca no campo `code` dentro da nova lista `products`.
* `"value": "products[#2].price"`: Pega o campo `value` e o grava como `price` dentro do mesmo item da lista.

Ao olhar **2 níveis acima**, o JOLT preserva o agrupamento original de cada produto ao formar a nova lista.

### **| (pipe)**

O operador `|` permite fazer referência a **múltiplos nomes de campo possíveis** no JSON de entrada e mapear todos eles para o **mesmo destino** no JSON de saída.

Isso é útil quando a estrutura de entrada pode variar, mas a saída precisa permanecer consistente.

* **Uso:** LHS
* **Operação:** `shift`

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

* **Caso de uso:** Tratar diferentes convenções de nomenclatura para o mesmo campo de cliente.
* **Objetivo:** Mapear `fullName` ou `customerName` para um campo unificado `name`.

**JSON de entrada**

```json
{
 "customer": {
   "fullName": "Customer Example",
   "email": "customer-example@email.com"
 }
}
```

**JSON de saída desejado**

```json
{
 "customer": {
   "name": "Customer Example",
   "email": "customer-example@email.com"
 }
}
```

**Spec de transformação**

```json
[
 {
   "operation": "shift",
   "spec": {
     "customer": {
       "fullName|customerName": "customer.nome",
       "email": "customer.&"
     }
   }
 }
]
```

**Explicação**

* `"fullName|customerName"` significa: se `fullName` **ou** `customerName` estiver presente, seu valor será atribuído a `customer.name`.
* `"email": "customer.&"` preserva o nome do campo e mapeia o valor de `email` como está.

Isso garante que a saída permaneça consistente mesmo quando a entrada usa diferentes convenções de nomenclatura.

## **Continue aprendendo**

Agora que você entende como esse operador funciona, aqui estão alguns próximos passos que você pode explorar:

* [**Operações avançadas**](https://docs.digibee.com/documentation/resources/pt-br/use-cases/how-to-jolt/advanced-operations), onde você aprofunda recursos de transformação mais poderosos.
* [**Exemplos de uso**](https://docs.digibee.com/documentation/resources/pt-br/use-cases/how-to-jolt/use-cases), mostrando como o JOLT é aplicado em cenários reais de integração.
