はじめに
2024年11月、AWS Step Functionsで新たにJSONataというクエリ言語が使用可能になりました。
https://aws.amazon.com/jp/about-aws/whats-new/2024/11/aws-step-functions-variables-jsonata-transformations/
現在はステートマシン作成時に既存のJSONPathとJSONataどちらも選べるようになっています。
しかし、新規作成されるステートマシンではこれまでのクエリ言語JSONPathではなくJSONataがデフォルト選択されるようになっており、AWSとしてもJSONataを推奨しているようです。
AWS StepFunctionsのコンソールで試せるHello WorldテンプレートでもJSONataが使用されています。
JSONataについては公式サイトトップに要点がまとめてあり、
https://jsonata.org/
- Lightweight query and transformation language for JSON data
- Inspired by the location path semantics of XPath 3.1
- Sophisticated query expressions with minimal syntax
- Built in operators and functions for manipulating and combining data
- Create user-defined functions
- Format query results into any JSON output structure
JSONデータを対象に、演算や結合・関数を用いてクエリやデータ変換を行うことができる言語のようです。
公式サイトトップの解説動画 JSONata in 5 minutesで基本要素を掴むことができます。
動画が英語版だったこともあり内容の要点を本記事にまとめてみました。
1 Play Groundを開く
下記URLでJSONataの練習を行うことができます。
開くと下記のようなページが表示されます。
赤線で分けている部分が今回扱うエリアとなります。
- 左側全体が「基となるJSONデータが表示されているエリア」
- 左側の右上に「データのテーマを切り替えることができるプルダウン」
- 右上が「クエリ言語を自由に入力できるエリア」
- 右下が「クエリを通したあとの出力エリア」
になっています。プルダウンで切り替えられるテーマは現在
- Invoice
- Address
- Schema
- Library
- Bindings
となっています。動画の中ではAddressとInvoiceが扱われています。
実際に手を動かしてみる
プルダウンでAddress
を選択します。
右上に例のサンプルクエリ
{
"name": FirstName & " " & Surname,
"mobile": Phone[type = "mobile"].number
}
が表示されていますが、一旦削除して、そこにSurname
と入力してみます。
すると、下記の文字列が出力されます。
"Smith"
このように元データのJSONのKeyであるSurname
をクエリ言語に設定すると、そのValueである文字列が出力できるようです。
ここまでは簡単ですね。
次は別のデータ種別を参照してみましょう。
右上のエリアにAddress
と入力します。すると、下記のようにオブジェクトが出力されます。
{
"Street": "Hursley Park",
"City": "Winchester",
"Postcode": "SO21 2JN"
}
ここまではJSONデータの直下のKeyに対する参照でしたが、一つ階層が深い、City
を参照したい場合について試してみます。
Address.City
とKeyをドットで繋いでクエリを入力してみます。
すると下記のようにAddress→Cityの階層のValueが出力できます。
"Winchester"
次に、文字列要素同士の結合を試します。
入力欄にFirstName & ' ' & Surname
と入力してみます。すると下記のようにFirstName、半角スペース、Surnameの形で出力されます。
"Fred Smith"
&
演算子を使って結合ができることが分かりました。
動画では出てきませんが、よりイメージが膨らむよう下記のように-
でつなげてみましょう
FirstName & '-' & Surname
を入力します。
すると下記のように-
つなぎで出力されることが分かります。
"Fred-Smith"
次に、Phone
を入力すると、オブジェクトの配列が取れます。
[
{
"type": "home",
"number": "0203 544 1234"
},
{
"type": "office",
"number": "01962 001234"
},
{
"type": "office",
"number": "01962 001235"
},
{
"type": "mobile",
"number": "077 7700 1234"
}
]
Phone.number
と入力すると、それぞれのオブジェクトのnumberを抽出し、文字列の配列として出力します。
[
"0203 544 1234",
"01962 001234",
"01962 001235",
"077 7700 1234"
]
動画には出てきませんが、同じ原理でPhone.type
と入力してみると下記のように出力されます。
[
"home",
"office",
"office",
"mobile"
]
JavaScriptのmap処理と同じ動きをしています。
const Phone = [
{ type: "home", number: "0203 544 1234" },
{ type: "office", number: "01962 001234" },
{ type: "office", number: "01962 001235" },
{ type: "mobile", number: "077 7700 1234" }
];
// すべての電話番号を取得
const numbers = Phone.map(phone => phone.number);
console.log(numbers);
// ["0203 544 1234", "01962 001234", "01962 001235", "077 7700 1234"]
配列の参照
Phone[0].number
と入力すると下記文字列が出力されます。配列の特定の要素には[i]
(iは任意の数値)でアクセスできるようです。
"0203 544 1234"
type
を使用したフィルタリングもできます。
Phone[type='mobile'].number
と入力すると、下記が出力されます。
"077 7700 1234"
Phone
の中で唯一typeがmobile
だったnumberの値を抽出できていることが分かります。
{
"type": "mobile",
"number": "077 7700 1234"
}
=
演算子を用いた比較ができることが分かりました。
公式サイトにはcomparison-expressions
として紹介されています。
動画ではここでInvoiceテーマのJSONデータに切り替えているので、左エリア右上のプルダウンでInvoice
を選択し、データの切り替えを行いましょう。
Account.Order.Product.Price
と入力してみます。すると、下記のように数値の配列が出力されます。
[
34.45,
21.67,
34.45,
107.99
]
商品の価格が出力されましたが、そこに数をかけ合わせてそれぞれの商品の合計金額を出力します。
Account.Order.Product.(Price * Quantity)
と入力してみましょう。
すると下記のようにPrice * Quantity
された数が配列として出力されています。
[
68.9,
21.67,
137.8,
107.99
]
こちらもJavaScriptのmapを使うと下記のように表現できます。
const Order = [
{ Product: { Price: 34.45, Quantity: 2 } },
{ Product: { Price: 21.67, Quantity: 1 } },
];
const totalPrices = Order.map(order => {
return order.Product.Price * order.Product.Quantity;
});
console.log(totalPrices);
// [68.9,21.67]
次は商品価格と商品数を踏まえた総額を出力します。
$sum(Account.Order.Product.(Price * Quantity))
と入力します。
すると下記のように総額が出力されます。
336.36
$sum
関数を使った演算ができることが分かりました。
この$sum()
はaggregation-functions
として定義されているJSONataの関数です。
他にもmax
,min
,average
などを使用することができます。
動画には出てきませんが
$max(Account.Order.Product.(Price * Quantity))
と入力してみましょう。
すると、
Account.Order.Product.(Price * Quantity)
で出力された
[
68.9,
21.67,
137.8,
107.99
]
の中の最大値である
137.8
が1件出力されます。
お疲れ様でした。ここで動画は終わっています。
終わりに
5分でJSONataについて簡単に試せる動画となっており、JSONataの感覚を掴むには最適なコンテンツでした。
様々な演算子や関数を使うことができるため、AWS StepFunctionsのみで値の計算を完結できるようになる気がします(今まではLambda等で加工していた)。
更にJSONataを使いこなすために、このPlayGroundで遊ぶのも良し、公式ドキュメントの読み込みや、Step Functionsのコンソール上で試してみるのも良さそうです!