AWS StepfunctionsのMapステートで、あるプロパティをmapで渡しながら、別のプロパティも全ての子に渡す
課題
- 配列の長さが 1 の場合、JSONata 式
$mapの評価結果が オブジェクトとして扱われる。 Mapステートでは、Itemsに 配列形式 が必須であるため、エラーが発生。
解決策
次の JSONata 式を使用することで、$map の結果が 常に配列形式 で返されるようにした
"Items": "{% $type($map($states.input.hoges, function($hoge) { $merge([$hoge, {\"fuga\": $states.input.fuga}]) })) = 'array' ? $map($states.input.hoges, function($hoge) { $merge([$hoge, {\"fuga\": $states.input.fuga}]) }) : [$map($states.input.hoges, function($hoge) { $merge([$hoge, {\"fuga\": $states.input.fuga}]) })] %}"
具体的な対応手順
-
$typeを使用して配列形式をチェック$type($map(...))で結果が'array'かどうかを判定。
-
配列でない場合は明示的にラップ
- オブジェクトで評価された場合は、
[...]を使って配列化。
- オブジェクトで評価された場合は、
-
$mergeを使用して追加フィールドを統合- 各要素に
fugaフィールドを追加するために$mergeを使用。
- 各要素に
最終的なステートマシンの設定例
{
"Comment": "A description of my state machine",
"StartAt": "Lambda Invoke",
"States": {
"Lambda Invoke": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Output": "{% $states.result.Payload %}",
"Arguments": {
"FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:test-lambda1:$LATEST",
"Payload": "{% $states.input %}"
},
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2,
"JitterStrategy": "FULL"
}
],
"Next": "Map"
},
"Map": {
"Type": "Map",
"ItemProcessor": {
"ProcessorConfig": {
"Mode": "INLINE"
},
"StartAt": "Lambda Invoke (1)",
"States": {
"Lambda Invoke (1)": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Output": "{% $states.result.Payload %}",
"Arguments": {
"FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:test-lambda2:$LATEST",
"Payload": "{% $states.input %}"
},
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2,
"JitterStrategy": "FULL"
}
],
"End": true
}
}
},
"End": true,
"Items": "{% $type($map($states.input.hoges, function($hoge) { $merge([$hoge, {\"fuga\": $states.input.fuga}]) })) = 'array' ? $map($states.input.hoges, function($hoge) { $merge([$hoge, {\"fuga\": $states.input.fuga}]) }) : [$map($states.input.hoges, function($hoge) { $merge([$hoge, {\"fuga\": $states.input.fuga}]) })] %}"
}
},
"QueryLanguage": "JSONata"
}
動作確認
以下の入力データで動作を確認済み:
-
hogesが複数要素の配列の場合{ "hoges": [ { "id": 1, "name": "Hoge A" }, { "id": 2, "name": "Hoge B" } ], "fuga": "example_fuga" }出力
[ { "id": 1, "name": "Hoge A", "fuga": "example_fuga" }, { "id": 2, "name": "Hoge B", "fuga": "example_fuga" } ] -
hogesが単一オブジェクトの場合{ "hoges": { "id": 1, "name": "Hoge A" }, "fuga": "example_fuga" }出力
[ { "id": 1, "name": "Hoge A", "fuga": "example_fuga" } ]
まとめ
要素数1でも、2~でも対応可能になった。