JSONata é uma linguagem de consulta e transformação de código aberto projetada para dados JSON que usaremos para acessar e analisar dados de um corpo de resposta JSON retornado pela API.
Você pode testar facilmente suas consultas usando https://try.jsonata.org/ ou, se preferir um formato mais sofisticado de Javascript, https://www.stedi.com/jsonata/playground. Vamos nos limitar ao exercício do próprio JSONata para esta introdução.
O exercício iniciará o objeto fictício Fatura, que usaremos como ponto de referência. Os dados brutos de entrada estão à esquerda, a consulta da expressão JSONata está no canto superior direito e o resultado encontrado por essa expressão será renderizado no canto inferior direito.
Para realinhar o objeto JSON, use a pequena ferramenta de recuo à direita do objeto fictício e salve qualquer expressão atual usando a funcionalidade de compartilhamento no canto superior direito.
Isso é tudo que você precisa saber sobre o exercício por enquanto. Em seguida, use uma consulta dentro do modelo de fatura padrão.
Se você está procurando apenas os principais aprendizados ou um ponto de referência após a ativação, consulte nossa folha de dicas.
Mapeamento de dados
Campo no nível raiz: Conta
Campo aninhado no objeto raiz: Account.'Nome da conta'
Se ele encontrar outra estrutura JSON, você poderá usar a notação de ponto para inserir os campos abaixo.
Campo aninhado em uma matriz de nível raiz:
Primeira ordem nesta conta:
Account.Order[0]
Lembrete A indexação de matriz começa em [0] para o primeiro item. O atalho para o último item em uma matriz é [-1].
A cor do primeiro produto neste mesmo objeto:
Account.Order[0].Product[0].Description.Colour
Recuperar uma matriz de itens de uma matriz de nível raiz:
Se vários valores corresponderem a uma consulta, o JSONata os agregará automaticamente.
Verifique todo o objeto Account.Order e recupere todas as OrderIDs nele:
Account.Order.OrderID
Filtragem de dados
Defina o alvo que está sendo acessado, por exemplo:
Account.Order.OrderID
Agora, adicione a condição no local correspondente. Para cada execução em uma matriz, adicione um par de colchetes []:
Por exemplo, incluir apenas pedidos com produtos com preço maior que 30 que foram pedidos apenas uma vez e mostrar o respectivo nome do produto:
Account.Order.Product[Price > 30 and Quantity = 1].'Product Name'
Por exemplo, incluir apenas pedidos com produtos com Description.Weight maior que 1 e mostrar o respectivo ID do pedido:
Account.Order[Product[Description.Weight > 1]].OrderID
Como alternativa, você também pode verificar se há uma declaração verdadeira, por exemplo:
Account.Order[Product["Purple" in Description.Colour]].OrderID
Além disso, isso pode ser combinado com pesquisas com curingas se você desejar verificar várias chaves, por exemplo:
Account.Order[Product["Purple" in Description.*]].OrderID
Outros operadores de caminho
(https://docs.jsonata.org/path-operators)
^( ... ) (Order-by)
Classificar por ordem decrescente de OrderID:
Account.Order^(>OrderID)
Classificar do produto mais barato para o mais caro:
Account.Order.Product^(Price)
* (Curinga)
Acessar qualquer SKU, independentemente da nomenclatura principal direta:
Account.Order.*.SKU
Acessar qualquer Product Name, independentemente de qualquer nome principal:
**.'Product Name'
% (Principal)
Pesquisa para trás na estrutura de dados atual:
Account.Order.Product.{
'Account': %.%.`Account Name`,
'Order': %.OrderID,
'Product': `Product Name`
}
# (Vinculação de variável posicional)
Cria um índice, começando em 0:
Account.Order#$i[Product.[Quantity > 0]].{
'Order ID': OrderID,
'Order Number': $i + 1
}
@ (Vinculação de variável de contexto)
Atribui temporariamente uma nova estrutura de dados, permitindo o mapeamentos entre objetos:
Account@$A.Account.Order@$O.{
"Account Name": $A.'Account Name',
"OrderID": $O.OrderID
}
Condicionais
Semelhante ao operador ternário no JS, você pode usar ? para "if" e : para "else". Os operadores booleanos "and/or" (e/ou) podem ser usados para criar condições em cadeia.
SE A CONDIÇÃO FOR VERDADEIRA? FAÇA ISTO (SENÃO, NÃO FAÇA NADA)
SE A CONDIÇÃO FOR VERDADEIRA? FAÇA ISTO: SENÃO, FAÇA ISSO
$count(Account.Order) > 1 ? "REPEAT CUSTOMER"
Account.Order[0].Product[0].Price <= 100 or Account.Order[0].Product[1].Price <= 100 ? "Bargain" : "VIP" = "Bargain"
Manipulação de dados
Operadores com suporte
Operador | Prioridade | Descrição |
Multiplicar (*) | 5 | Multiplica dois números |
Dividir (/) | 5 | Divide dois números |
Módulo (%) | 5 | Retorna o resto ao dividir dois números |
Concatenar (&) | 4 | Concatena duas cadeias de caracteres |
Somar (+) | 4 | Soma dois números |
Subtrair (-) | 4 | Subtrai dois números |
Igual a (=) | 3 | Testa se dois valores são iguais |
É diferente de (!=) | 3 | Testa se dois valores não são iguais |
Maior que (>) | 3 | Retorna "verdadeiro" se o valor à esquerda for maior que o valor à direita |
Maior ou igual a (>=) | 3 | Retorna "verdadeiro" se o valor à esquerda for maior ou igual ao valor à direita |
Menor que (<) | 3 | Retorna verdadeiro se o valor à esquerda for menor que o valor à direita |
Menor ou igual a (<=) | 3 | Retorna verdadeiro se o valor à esquerda for menor ou igual ao valor à direita |
AND lógico (e) | 2 | Retorna verdadeiro se os valores à esquerda e à direita forem verdadeiros |
OR lógico (ou) | 1 | Retorna verdadeiro se o valor à esquerda for verdadeiro ou o valor à direita for verdadeiro |
Por exemplo, para concatenar cadeias de caracteres:
Account.Order[0].Product[0].Description.Colour & " " & Account.Order[0].Product[0].'Product Name'
Funções incorporadas
Observe que essas informações foram muito resumidas para facilitar a leitura. A documentação completa pode ser encontrada aqui: https://docs.jsonata.org/overview.html.
Observação: uma expressão de várias linhas precisa ser agrupada em ().
Forçar tipo de cadeia de caracteres: $string(Account.Order[0].Product[0].ProductID): "858383"
Forçar tipo de número: $number(Account.Order[0].Product[0].SKU): 406654608
Cadeia de caracteres em caixa alta: $uppercase(Account.Order[0].OrderID): "ORDER103"
Cadeia de caracteres em minúsculas: $lowercase(Account.Order[0].Product[0].Description.Colour): "roxo"
Número aleatório de saída entre 0 e 1: $random()
Contar objetos em uma matriz: $count(Account.Order)
Contar objetos em uma matriz que correspondem a uma condição: $count(Account.Order.Product[Price > 30])
Número de caracteres em uma cadeia de caracteres: $length(Account.'Nome da conta')
Substituir/remover determinados caracteres em uma cadeia de caracteres: $replace(Account.Order[0].Product[0].'Nome do produto', "Chapéu-coco ", ""): "Chapéu"
Corte de uma cadeia de caracteres na contagem de caracteres específicos: $substring($string(Account.Order[0].Product[0].ProductID), 1, 2)
Corte de uma cadeia de caracteres em um padrão específico: $substringAfter(Account.Order[0].OrderID, "pedido")
Resultado semelhante usando "split" + "join":
$join($split(Account.Order[0].Product[0].'Nome do produto', " "), '_')
Também pode ser escrito como ~> função:
$split(Account.Order[0].Product[0].'Nome do produto', " ") ~> $join('_')
Verifique se uma cadeia de caracteres contém um padrão específico, que pode ser uma cadeia de caracteres exata ou uma expressão regular:
$contains(Account.Order[0].Product[0].'Nome do produto', "Chapéu")
Datas e horários
A maioria das datas será aprovada no padrão internacional ISO 8601 e terá este formato: 2023-04-20T13:09:39+00:00 (carregando informações de fuso horário) ou 2023-04-20T13:09:39Z (compensado em milissegundos em relação ao UTC). Elas são legíveis por humanos, mas não podem ser manipuladas nativamente pelo JSONata.
Muitas vezes, você terá que transformá-las em horário UNIX, que é o número literal de segundos decorridos desde 00:00:00 UTC em 1º de janeiro de 1970 (Unix Epoch). Isso não é mais legível por humanos, mas, por ser um número inteiro, pode ser somado/subtraído/comparado a outras datas do UNIX. O JSONata funciona nativamente com Millis, que são os MILISSEGUNDOS desde Unix Epoch (portanto, UNIX * 1000).
$now(): "2023-04-20T13:39:58.216Z"
$millis(): 1681998518175
Esses milissegundos agora podem ser transformados novamente em um formato de data de sua escolha definindo uma imagem (seu padrão alvo) em uma cadeia de caracteres: https://www.w3.org/TR/xpath-functions-31/#date-picture-string
Exemplos de padrões: https://www.w3.org/TR/xpath-functions-31/#date-time-examples
Especificador | Significado |
S |
Ano (valor absoluto) |
M | Mês do ano |
D | Dia do mês |
F | Dia da semana |
H | Hora do dia (24 horas) |
h | Hora em meio dia (12 horas) |
P | Marcador AM/PM |
m | Minuto da hora |
s | Segundo em minuto |
Z | Fuso horário |
por exemplo, $fromMillis($millis(), '[M]/[D]/[Y01]') retornará "4/20/23",
$fromMillis($millis(), '[D01].[M01].[Y0001] [H#1]:[m01]') retornará "20.04.2023 13:51".
Colocando isso em prática, digamos que você tenha duas datas em seus dados de resposta e queira verificar quantos dias se passaram desde TODAY (hoje).
"2023-04-20T00:00:00.000Z"
"20.04.2023"
Transforme as duas em Milis. A segunda data não está no padrão ISO 8601, então você precisará fornecer a imagem para que o JSONata saiba qual valor é o dia, o mês, o ano e qualquer informação de tempo você pode ter disponível.
$toMillis('2023-04-20T00:00:00.000Z'): 1681948800000
$toMillis('20.04.2023', '[D01].[M01].[Y0001]'): 1681948800000
Você também tem a hora atual em Milis por meio da função padrão $millis(): 1681999968402
Agora você pode simplesmente subtrair uma da outra e receber a diferença entre as duas datas em milissegundos: 1681999968402 - 1681948800000 = 51296367
Uso da conversão de tempo comum:
1000 milissegundos = 1 segundo
60 s = 1 minuto
60 min = 1 hora
E, arredondando o resultado para baixo, ficaria: 14 horas se passaram entre agora e o carimbo de data/hora fornecido:
$round(51296367 / 1000 / 60 / 60) = 14
Combinados em uma linha, você verá uma operação de:
$round(($millis() - $toMillis('20.04.2023', '[D01].[M01].[Y0001]')) / 1000 / 60 / 60)
Saídas especiais
Ticket “Oneliners”
Como você pode ter apenas uma chance de responder, passe o máximo de informações possível em um único parâmetro. O JSONata lida com a agregação para que você possa testar livremente a cópia de texto.
Digamos que você queira renderizar os SKUs e os preços de todos os produtos em seu pedido:
Account.Order.Product
Como você só quer ter uma grande linha de texto com todos os produtos considerados, pode simplesmente criar uma matriz compartilhada com todas as informações necessárias:
Account.Order.Product.(SKU & Price)
Agora, você só precisa combiná-los em uma grande cadeia de caracteres com um caractere de quebra de linha como separador:
$join(Account.Order.Product.("SKUs: " & SKU & ", " & "Price: " & Price), "\n")
Observação: Considere as limitações de seus CRMs. O Zendesk Support oferece alguma formatação básica, então um \n será traduzido corretamente em uma quebra de linha ao renderizar um e-mail de resposta, mas esse pode não ser o caso em todos os sistemas.
Cartões e carrosséis
Cartões e carrosséis são a verdadeira força do JSONata, pois ele lida com a consulta e a agregação de dados nativamente, desde que sua resposta siga o mesmo esquema. Um C&C consiste em uma matriz de objetos na qual cada objeto representa um de seus cartões. Um exemplo muito simples de uma estrutura de C&C com dois cartões poderia ser mais ou menos assim:
[
{
"imageURL": data.url1,
"title": data.title1,
"description": data.description1
},
{
"imageURL": data.url2,
"title": data.title2,
"description": data.description2
}
]
O importante é que todos os objetos na matriz sigam a mesma estrutura para que possam ser acessados por meio da mesma chave compartilhada. Lembre-se também das limitações do seu CRM.
Para um exemplo direto, vamos criar um C&C nos dados de exemplo da fatura novamente. Vamos começar com uma matriz desde o início. Qualquer resultado de consulta com mais de um objeto de resposta será convertido automaticamente em uma matriz, mas é bom ter essa proteção contra falhas caso seu resultado carregue apenas um objeto sozinho.
[Account.Order.Product.'Product Name']
[Account.Order.Product.SKU]
[Account.Order.Product.Description.Colour]
Estes são alguns dos campos nos quais estamos interessados. Vamos combiná-los em um objeto. Certifique-se de dar um nome a cada chave em seu objeto de destino:
[
Account.Order.Product.
{
"name": 'Product Name',
"sku": SKU,
"colour": Description.Colour
}
]
Se você precisar de um valor um nível superior, basta iniciar sua consulta em um nível superior. Se você também deseja incluir [Account.Order.OrderID] em sua matriz:
[
Account.Order.
{
"orderId": OrderID,
"name": Product.'Product Name',
"sku": Product.SKU,
"Colour": Product.Description.Colour
}
]
Você notará que não há mais correspondência direta de 1:1, pois cada pedido pode conter vários itens, e é por isso que essa resposta cria matrizes de cadeias de caracteres aparentemente aleatórias. Você pode resolver isso acessando o objeto pai indiretamente (consulte vinculação pai), atribuindo temporariamente uma estrutura de objeto diferente em JSONata (consulte vinculação de variável de contexto), adicionando um C&C secundário que percorre os itens na ordem escolhida ou transformando mais os dados, dependendo da sua experiência de usuário ideal. Aqui está um exemplo transformado:
[
Account.Order.
{
"orderId": OrderID,
"name": $join(Product.'Product Name', ", "),
"totalPrice": $sum(Product.Price)
}
]
Se você quiser proteger ainda mais sua consulta, vamos adicionar alguns itens de segurança caso não tenha os dados de resposta esperados (para cobrir, por exemplo, um 404), além de um ponto de corte caso a resposta retorne mais resultados do que seu CRM pode suportar (por exemplo, 10 para widgets da SunCo):
Account.Order ?
[Account.Order[[0..9]].
{
"orderId": OrderID,
"name": $join(Product.'Product Name', ", "),
"totalPrice": $sum(Product.Price)}]
: [{"orderId": "???", "name": "Cannot find your item?"}]
IMPORTANTE: certifique-se de que todas as chaves C&C sigam a convenção camelCase, _ nomes de parâmetros não são suportados.
Agora, todas essas chaves, por exemplo, orderId, name, totalPrice, estarão disponíveis para seu carrossel. Altere seu tipo de carrossel para dinâmico na interface do usuário e adicione o nome do parâmetro que hospeda sua consulta acima, por exemplo, orderList.
Agora você pode acessar qualquer chave nos objetos de sua matriz adicionando um % abreviado - ou gerando-os diretamente no chat em seus cartões:
Ou armazenando-os na sessão, preenchendo o cartão de sua escolha com uma ação que faz referência à chave do objeto escolhido em um nome de parâmetro de sua escolha, por exemplo: