View a markdown version of this page

Trasformazione dei dati con JSonata in Step Functions - AWS Step Functions

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Trasformazione dei dati con JSonata in Step Functions

Con JSonata, ottieni un potente linguaggio di query ed espressione open source per selezionare e trasformare i dati nei tuoi flussi di lavoro. Per una breve introduzione e un riferimento completo a JSonata, consulta la documentazione. JSONata.org

Versione JSonata supportata

Step Functions supporta JSonata versione 2.0.6.

Il video seguente descrive le variabili e JSonata in Step Functions con un esempio di DynamoDB:

È necessario attivare l'utilizzo del linguaggio di query e trasformazione JSonata per i flussi di lavoro esistenti. Quando crei un flusso di lavoro nella console, ti consigliamo di scegliere JSonata per la macchina a stati di primo livello. QueryLanguage Per i flussi di lavoro esistenti o nuovi che utilizzano JSONPath, la console offre un'opzione per convertire i singoli stati in JSonata.

Dopo aver selezionato JSonata, i campi del flusso di lavoro verranno ridotti da cinque campi JsonPath (InputPath,, Parameters ResultSelectorResultPath, e) a soli due campi: e. OutputPath Arguments Output Inoltre, non verranno utilizzati i nomi delle chiavi degli oggetti .$ JSON.

Se non conosci Step Functions, devi solo sapere che le espressioni JSONATA utilizzano la seguente sintassi:

Sintassi JSonata: "{% <JSONata expression> %}"

I seguenti esempi di codice mostrano una conversione da JSONPath a JSONata:

# Original sample using JSONPath { "QueryLanguage": "JSONPath", // Set explicitly; could be set and inherited from top-level "Type": "Task", ... "Parameters": { "static": "Hello", "title.$": "$.title", "name.$": "$customerName", // With $customerName declared as a variable "not-evaluated": "$customerName" } }
# Sample after conversion to JSONata { "QueryLanguage": "JSONata", // Set explicitly; could be set and inherited from top-level "Type": "Task", ... "Arguments": { // JSONata states do not have Parameters "static": "Hello", "title": "{% $states.input.title %}", "name": "{% $customerName %}", // With $customerName declared as a variable "not-evaluated": "$customerName" } }

Dato l'input { "title" : "Doctor" } e la variabile customerName assegnata a"María", entrambe le macchine a stati produrranno il seguente risultato JSON:

{ "static": "Hello", "title": "Doctor", "name": "María", "not-evaluated": "$customerName" }

Nel diagramma seguente, puoi vedere una rappresentazione grafica che mostra come la conversione di JsonPath (a sinistra) in JSONata (a destra) ridurrà la complessità dei passaggi nelle tue macchine a stati:

Diagramma che confronta i campi negli stati JsonPath e JSonata.

È possibile (facoltativamente) selezionare e trasformare i dati dall'input di stato in Arguments da inviare all'azione integrata. Con JSonata, puoi quindi (facoltativamente) selezionare e trasformare i risultati dell'azione per l'assegnazione alle variabili e per l'output dello stato.

Nota: le fasi di assegnazione e di uscita avvengono in parallelo. Se scegli di trasformare i dati durante l'assegnazione delle variabili, tali dati trasformati non saranno disponibili nella fase di output. È necessario riapplicare la trasformazione JSonata nella fase di output.

Diagramma logico di uno stato che utilizza il linguaggio di interrogazione JSonata.

QueryLanguage campo

Nelle definizioni ASL del flusso di lavoro, c'è un QueryLanguage campo al livello superiore della definizione di una macchina a stati e nei singoli stati. Impostando i QueryLanguage singoli stati, puoi adottare JSONATA in modo incrementale in una macchina a stati esistente anziché aggiornare la macchina a stati tutta in una volta.

Il QueryLanguage campo può essere impostato su o. "JSONPath" "JSONata" Se il QueryLanguage campo di primo livello viene omesso, il valore predefinito è. "JSONPath" Se uno stato contiene un QueryLanguage campo a livello di stato, Step Functions utilizzerà il linguaggio di interrogazione specificato per quello stato. Se lo stato non contiene un QueryLanguage campo, utilizzerà il linguaggio di interrogazione specificato nel campo di primo livelloQueryLanguage.

Scrittura di espressioni JSonata in stringhe JSON

Quando una stringa nel valore di un campo ASL, un campo oggetto JSON o un elemento dell'array JSON è circondata da {% %} caratteri, quella stringa verrà valutata come JSonata. Nota, la stringa deve iniziare {% senza spazi iniziali e deve terminare senza spazi finali. %} L'apertura o la chiusura errata dell'espressione genereranno un errore di convalida.

Alcuni esempi:

  • "TimeoutSeconds" : "{% $timeout %}"

  • "Arguments" : {"field1" : "{% $name %}"}in uno stato Task

  • "Items": [1, "{% $two %}", 3]in uno Map stato

Non tutti i campi ASL accettano JSonata. Ad esempio, il Type campo di ogni stato deve essere impostato su una stringa costante. Analogamente, il Resource campo Task dello stato deve essere una stringa costante. Il Items campo di Map stato accetterà un array JSON, un oggetto JSON o un'espressione JSONata che deve restituire un array o un oggetto.

Variabile riservata: $states

Step Functions definisce una singola variabile riservata chiamata $states. Negli stati JSonata, le seguenti strutture vengono assegnate $states per l'uso nelle espressioni JSonata:

# Reserved $states variable in JSONata states $states = { "input": // Original input to the state "result": // API or sub-workflow's result (if successful) "errorOutput": // Error Output (only available in a Catch) "context": // Context object }

All'ingresso dello stato, Step Functions assegna l'input di stato a $states.input. Il valore di $states.input può essere utilizzato in tutti i campi che accettano espressioni JSonata. $states.inputsi riferisce sempre all'input di stato originale.

Per TaskParallel, e Map afferma:

  • $states.resultfa riferimento al risultato non elaborato dell'API o del flusso di lavoro secondario in caso di successo.

  • $states.errorOutputfa riferimento all'Error Output se l'API o il sottoflusso di lavoro non sono riusciti.

    $states.errorOutputpuò essere utilizzato nel Catch campo Assign oOutput.

Il tentativo di accedere $states.result a campi e stati $states.errorOutput in cui non sono accessibili verrà interrotto al momento della creazione, dell'aggiornamento o della convalida della macchina a stati.

L'$states.contextoggetto fornisce ai flussi di lavoro informazioni sulla loro esecuzione specifica, ad esempio il token dell'attività e l'input iniziale del flusso di lavoro. StartTime Per ulteriori informazioni, consultaAccesso ai dati di esecuzione dall'oggetto Context in Step Functions.

Gestione degli errori di espressione

In fase di esecuzione, la valutazione dell'espressione JSonata potrebbe non riuscire per una serie di motivi, ad esempio:

  • Errore di tipo: un'espressione, ad esempio{% $x + $y %}, avrà esito negativo se $y è $x o non è un numero.

  • Incompatibilità tra tipi: un'espressione potrebbe restituire un tipo che il campo non accetterà. Ad esempio, il campo TimeoutSeconds richiede un input numerico, quindi l'espressione {% $timeout %} avrà esito negativo se $timeout restituisce una stringa.

  • Valore non compreso nell'intervallo: un'espressione che produce un valore che non rientra nell'intervallo accettabile per un campo avrà esito negativo. Ad esempio, un'espressione come non {% $evaluatesToNegativeNumber %} riuscirà nel TimeoutSeconds campo.

  • Mancata restituzione di un risultato: JSON non può rappresentare un'espressione di valore indefinita, pertanto l'espressione {% $data.thisFieldDoesNotExist %} genererebbe un errore.

  • Limite di memoria superato: un'espressione JSONATA che consuma troppa memoria durante la valutazione avrà esito negativo e restituirà un errore. Expression evaluation memory limit exceeded Ciò può verificarsi con espressioni che elaborano o trasformano grandi quantità di dati. Per ovviare a questa limitazione, valuta la possibilità di spostare la trasformazione dei dati in una funzione Lambda.

  • Timeout dell'espressione: un'espressione JSonata che impiega più di 1 secondo per la valutazione avrà esito negativo e restituirà un errore. Expression evaluation timeout Ciò può verificarsi con espressioni che contengono loop infiniti o operazioni molto costose.

  • Stack overflow: un'espressione JSonata che supera la profondità di ricorsione massima fallirà con a. Stack overflow error Se la ricorsione non termina, assicurati che la funzione abbia un maiuscolo base o una condizione di terminazione corretti. Se la ricorsione termina ma lo stack di chiamate diventa troppo profondo, prendi in considerazione la possibilità di riscrivere la funzione come ricorsiva in coda per ridurre la profondità dello stack.

In ogni caso, l'interprete genererà l'errore:. States.QueryEvaluationError Gli stati Task, Map e Parallel possono fornire un Catch campo per catturare l'errore e un Retry campo per riprovare l'errore.

Conversione da JsonPath a JSONata

Le sezioni seguenti confrontano e spiegano le differenze tra il codice scritto con JsonPath e JSonata.

Niente più campi di percorso

ASL richiede agli sviluppatori di utilizzare Path versioni dei campi, ad esempioTimeoutSecondsPath, per selezionare un valore dai dati di stato quando utilizzano JsonPath. Quando usi JSonata, non usi più Path i campi perché ASL interpreterà automaticamente le espressioni JSONATA {% %} racchiuse per te in campi non Path, come. TimeoutSeconds

  • Esempio precedente di JsonPath: "TimeoutSecondsPath": "$timeout"

  • JSONATA: "TimeoutSeconds": "{% $timeout %}"

Allo stesso modo, lo Map ItemsPath stato è stato sostituito con il Items campo che accetta un array JSON, un oggetto JSON o un'espressione JSONata che deve restituire un array o un oggetto.

Oggetti JSON

ASL utilizza il termine modello di payload per descrivere un oggetto JSON che può contenere espressioni JSONPath per e valori di campo. Parameters ResultSelector ASL non utilizzerà il termine modello di payload per JSonata perché la valutazione JSonata avviene per tutte le stringhe, indipendentemente dal fatto che si verifichino da sole o all'interno di un oggetto JSON o di un array JSON.

Non più. $

ASL richiede di aggiungere '.$' ai nomi dei campi nei modelli di payload per utilizzare JsonPath e Intrinsic Functions. Quando si specifica"QueryLanguage":"JSONata", non si utilizza più la convenzione '.$' per i nomi dei campi degli oggetti JSON. Invece, racchiudi le espressioni JSonata tra caratteri. {% %} Utilizzate la stessa convenzione per tutti i campi con valori di stringa, indipendentemente dalla profondità con cui l'oggetto è annidato all'interno di altri array o oggetti.

Argomenti e campi di output

Quando QueryLanguage è impostato suJSONata, i vecchi campi di I/O elaborazione verranno disabilitati (InputPath, ParametersResultSelector, ResultPath eOutputPath) e la maggior parte degli stati riceverà due nuovi campi: Arguments eOutput.

JSonata offre un modo più semplice per eseguire I/O trasformazioni rispetto ai campi utilizzati con JsonPath. Le funzionalità di JSonata lo rendono Arguments Output più efficiente rispetto ai cinque campi precedenti con JsonPath. Questi nuovi nomi di campo aiutano anche a semplificare l'ASL e a chiarire il modello per il passaggio e la restituzione di valori.

I Output campi Arguments and (e altri campi simili come quelli di Map stateItemSelector) accetteranno un oggetto JSON come:

"Arguments": { "field1": 42, "field2": "{% jsonata expression %}" }

In alternativa, puoi usare direttamente un'espressione JSONata, ad esempio:

"Output": "{% jsonata expression %}"

Output può anche accettare qualsiasi tipo di valore JSON, ad esempio:,. "Output":true "Output":42

I Output campi Arguments and supportano solo JSONata, quindi non è valido utilizzarli con flussi di lavoro che utilizzano JSONPath. Al contrario,,, InputPath Parameters ResultSelector ResultPathOutputPath, e altri campi JSONPath sono supportati solo in JsonPath, quindi non è valido utilizzare campi basati sul percorso quando si utilizza JSONata come flusso di lavoro di primo livello o linguaggio di interrogazione statale.

Stato Pass

Lo stato opzionale Result in a Pass veniva precedentemente considerato come l'output di un'attività virtuale. Con JSonata selezionato come linguaggio di lavoro o di interrogazione di stato, ora puoi utilizzare il nuovo campo Output.

Stato della scelta

Quando si utilizza JsonPath, gli stati di scelta hanno un input Variable e numerosi percorsi di confronto, come i seguenti: NumericLessThanEqualsPath

# JSONPath choice state sample, with Variable and comparison path "Check Price": { "Type": "Choice", "Default": "Pause", "Choices": [ { "Variable": "$.current_price.current_price", "NumericLessThanEqualsPath": "$.desired_price", "Next": "Send Notification" } ], }

Con JSonata, lo stato di scelta ha un Condition punto in cui è possibile utilizzare un'espressione JSonata:

# Choice state after JSONata conversion "Check Price": { "Type": "Choice", "Default": "Pause" "Choices": [ { "Condition": "{% $current_price <= $states.input.desired_priced %}", "Next": "Send Notification" } ]

Nota: le variabili e i campi di confronto sono disponibili solo per JsonPath. La condizione è disponibile solo per JSonata.

Esempi in formato JSonata

I seguenti esempi possono essere creati in Workflow Studio per sperimentare con JSonata. È possibile creare ed eseguire le macchine a stati oppure utilizzare lo stato Test per trasmettere dati e persino modificare la definizione della macchina a stati.

Esempio: input e output

Questo esempio mostra come $states.input utilizzare l'input dello stato e il Output campo per specificare l'output dello stato quando si sceglie JSonata.

{ "Comment": "Input and Output example using JSONata", "QueryLanguage": "JSONata", "StartAt": "Basic Input and Output", "States": { "Basic Input and Output": { "QueryLanguage": "JSONata", "Type": "Succeed", "Output": { "lastName": "{% 'Last=>' & $states.input.customer.lastName %}", "orderValue": "{% $states.input.order.total %}" } } } }

Quando il flusso di lavoro viene eseguito con quanto segue come input:

{ "customer": { "firstName": "Martha", "lastName": "Rivera" }, "order": { "items": 7, "total": 27.91 } }

L'esecuzione dello stato di test o della macchina a stati restituirà il seguente output JSON:

{ "lastName": "Last=>Rivera", "orderValue": 27.91 }
Schermata che mostra l'input e l'output di uno stato in fase di test.

Esempio: filtraggio con JSONATA

Puoi filtrare i tuoi dati con gli operatori JSonata Path. Ad esempio, immagina di avere un elenco di prodotti da inserire e di voler elaborare solo prodotti che contengono zero calorie. È possibile creare una definizione di macchina a stati con il seguente ASL e testare FilterDietProducts lo stato con l'input di esempio che segue.

Definizione di macchina a stati per il filtraggio con JSonata

{ "Comment": "Filter products using JSONata", "QueryLanguage": "JSONata", "StartAt": "FilterDietProducts", "States": { "FilterDietProducts": { "Type": "Pass", "Output": { "dietProducts": "{% $states.input.products[calories=0] %}" }, "End": true } } }

Esempio di input per il test

{ "products": [ { "calories": 140, "flavour": "Cola", "name": "Product-1" }, { "calories": 0, "flavour": "Cola", "name": "Product-2" }, { "calories": 160, "flavour": "Orange", "name": "Product-3" }, { "calories": 100, "flavour": "Orange", "name": "Product-4" }, { "calories": 0, "flavour": "Lime", "name": "Product-5" } ] }

Risultato del test della fase sulla vostra macchina a stati

{ "dietProducts": [ { "calories": 0, "flavour": "Cola", "name": "Product-2" }, { "calories": 0, "flavour": "Lime", "name": "Product-5" } ] }
Esempio di output per le espressioni JSonata in fase di test.

Esempio: utilizzo dell'output dello stato precedente in uno stato della mappa

Questo esempio mostra come utilizzare l'output di uno stato precedente come input per uno stato della mappa con JSonata. Il seguente flusso di lavoro utilizza uno stato Pass per simulare un'attività che restituisce un ordine con un elenco di elementi, quindi uno stato Map seleziona l'array di elementi da quell'output e lo esegue su di esso.

Definizione della macchina a stati

{ "Comment": "Example: Using previous state output in a Map state with JSONata", "QueryLanguage": "JSONata", "StartAt": "GetOrder", "States": { "GetOrder": { "Type": "Pass", "Output": { "orderId": "{% $states.input.orderId %}", "items": "{% $states.input.items %}" }, "Next": "ProcessItems" }, "ProcessItems": { "Type": "Map", "Items": "{% $states.input.items %}", "ItemProcessor": { "ProcessorConfig": { "Mode": "INLINE" }, "StartAt": "CalculateItemTotal", "States": { "CalculateItemTotal": { "Type": "Pass", "Output": { "name": "{% $states.input.name %}", "total": "{% $states.input.price * $states.input.quantity %}" }, "End": true } } }, "End": true } } }

In questa definizione, lo GetOrder stato restituisce i dati dell'ordine invariati. Lo stato della ProcessItems mappa viene utilizzato "Items": "{% $states.input.items %}" per selezionare l'itemsarray dall'output di. GetOrder Ogni iterazione riceve un elemento dall'array e calcola il totale dell'articolo moltiplicando il prezzo per la quantità.

Esempio di input

{ "orderId": "ORD-1234", "items": [ { "name": "Widget", "price": 4.99, "quantity": 3 }, { "name": "Gadget", "price": 12.50, "quantity": 2 }, { "name": "Bolt", "price": 0.75, "quantity": 10 } ] }

Output previsto

[ { "name": "Widget", "total": 14.97 }, { "name": "Gadget", "total": 25 }, { "name": "Bolt", "total": 7.5 } ]

Esempio: appiattimento dell'output in stato parallelo

Quando si utilizza uno stato parallelo, restituisce un array in cui ogni elemento è l'output di un ramo. Con JSonata, puoi utilizzare il Output campo sullo stato Parallel per appiattire o unire questi risultati in un unico oggetto. Questo approccio sostituisce il campo JsonPath. ResultSelector

L'esempio seguente utilizza uno stato Parallel con due rami. Ogni ramo simula una chiamata GetItem DynamoDB utilizzando uno stato Pass. Lo stato Parallel utilizza $merge($states.result) nel suo Output campo per unire i risultati del ramo in un unico oggetto.

Definizione di macchina a stati

{ "Comment": "Example: Flattening Parallel state output with JSONata", "QueryLanguage": "JSONata", "StartAt": "GetOrderAndCustomer", "States": { "GetOrderAndCustomer": { "Type": "Parallel", "Output": "{% $merge($states.result) %}", "Branches": [ { "StartAt": "Get Order", "States": { "Get Order": { "Type": "Pass", "Output": { "orderId": "{% $states.input.orderId %}", "orderDate": "2024-11-20", "total": 35.99 }, "End": true } } }, { "StartAt": "Get Customer", "States": { "Get Customer": { "Type": "Pass", "Output": { "customerId": "{% $states.input.customerId %}", "customerName": "Martha Rivera", "email": "martha@example.com" }, "End": true } } } ], "Next": "Done" }, "Done": { "Type": "Succeed" } } }

Esempio di input

{ "orderId": "12345", "customerId": "C-100" }

Output previsto

{ "orderId": "12345", "orderDate": "2024-11-20", "total": 35.99, "customerId": "C-100", "customerName": "Martha Rivera", "email": "martha@example.com" }

La $merge() funzione combina una serie di oggetti in un unico oggetto. Se i rami restituiscono oggetti con chiavi sovrapposte, gli elementi dell'array successivi hanno la precedenza. I risultati dei rami vengono ordinati in modo coerente: corrispondono all'ordine dell'Branchesarray nella definizione della macchina a stati.

Funzioni JSonata fornite da Step Functions

JSonata contiene librerie di funzioni per le funzioni String, Numeric, Aggregation, Boolean, Array, Object e High Order. Date/Time Step Functions fornisce funzioni JSonata aggiuntive che puoi usare nelle tue espressioni JSonata. Queste funzioni integrate sostituiscono le funzioni intrinseche di Step Functions. Le funzioni intrinseche sono disponibili solo negli stati che utilizzano il linguaggio di query JsonPath.

Nota: le funzioni Built-in JSonata che richiedono valori interi come parametri arrotonderanno automaticamente per difetto tutti i numeri non interi forniti.

$partition - Equivalente in JSonata alla funzione intrinseca per partizionare un array di grandi dimensioni. States.ArrayPartition

Il primo parametro è l'array da partizionare, il secondo parametro è un numero intero che rappresenta la dimensione del blocco. Il valore restituito sarà un array bidimensionale. L'interprete suddivide l'array di input in più array della dimensione specificata dalla dimensione del blocco. La lunghezza dell'ultimo blocco dell'array può essere inferiore alla lunghezza dei blocchi dell'array precedente se il numero di elementi rimanenti nell'array è inferiore alla dimensione del blocco.

"Assign": { "arrayPartition": "{% $partition([1,2,3,4], $states.input.chunkSize) %}" }

$range - Equivalente JSonata alla funzione States.ArrayRange intrinseca per generare un array di valori.

Questa funzione richiede tre argomenti. Il primo argomento è un numero intero che rappresenta il primo elemento del nuovo array, il secondo argomento è un numero intero che rappresenta l'elemento finale del nuovo array e il terzo argomento è il valore intero del valore delta per gli elementi del nuovo array. Il valore restituito è una matrice di valori appena generata che va dal primo argomento della funzione al secondo argomento della funzione con elementi intermedi regolati dal delta. Il valore delta può essere positivo o negativo, il che incrementerà o decrementerà ogni elemento dall'ultimo fino al raggiungimento o al superamento del valore finale.

"Assign": { "arrayRange": "{% $range(0, 10, 2) %}" }

$hash - Equivalente JSONata della funzione States.Hash intrinseca per calcolare il valore hash di un determinato input.

Questa funzione accetta due argomenti. Il primo argomento è la stringa sorgente da sottoporre a hash. Il secondo argomento è una stringa che rappresenta l'algoritmo di hashing utilizzato per il calcolo dell'hash. L'algoritmo di hashing deve avere uno dei seguenti valori:"MD5",,,"SHA-1","SHA-256". "SHA-384" "SHA-512" Il valore restituito è una stringa dell'hash calcolato dei dati.

Questa funzione è stata creata perché JSonata non supporta nativamente la capacità di calcolare gli hash.

"Assign": { "myHash": "{% $hash($states.input.content, $hashAlgorithmName) %}" }

$random - Equivalente JSonata della funzione States.MathRandom intrinseca per restituire un numero casuale n dove. 0 ≤ n < 1

La funzione accetta un argomento intero opzionale che rappresenta il valore iniziale della funzione casuale. Se si utilizza questa funzione con lo stesso valore iniziale, restituisce un numero identico.

Questa funzione sovraccaricata è stata creata perché la funzione JSonata integrata $randomnon accetta un valore iniziale.

"Assign": { "randNoSeed": "{% $random() %}", "randSeeded": "{% $random($states.input.seed) %}" }

$uuid - Versione JSonata della funzione intrinseca. States.UUID

La funzione non accetta argomenti. Questa funzione restituisce un UUID v4.

Questa funzione è stata creata perché JSonata non supporta nativamente la capacità di generare UUID.

"Assign": { "uniqueId": "{% $uuid() %}" }

$parse - Funzione JSonata per deserializzare le stringhe JSON.

La funzione accetta un codice JSON con stringhe come unico argomento.

JSonata supporta questa funzionalità tramite$eval; tuttavia, non $eval è supportata nei flussi di lavoro Step Functions.

"Assign": { "deserializedPayload": "{% $parse($states.input.json_string) %}" }