$ cat "dev63.hatenablog.com/entry/2025/01/23/233551.md"
// ブログエントリー — 2025/1/23

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}]) })] %}"

具体的な対応手順

  1. $type を使用して配列形式をチェック

    • $type($map(...)) で結果が 'array' かどうかを判定。
  2. 配列でない場合は明示的にラップ

    • オブジェクトで評価された場合は、[...] を使って配列化。
  3. $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"
}

動作確認

以下の入力データで動作を確認済み:

  1. 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" }
    ]
    
  2. hoges が単一オブジェクトの場合

    {
      "hoges": { "id": 1, "name": "Hoge A" },
      "fuga": "example_fuga"
    }
    

    出力

    [
      { "id": 1, "name": "Hoge A", "fuga": "example_fuga" }
    ]
    

まとめ

要素数1でも、2~でも対応可能になった。

ENTRY: dev63.hatenablog.com/entry/2025/01/23/233551.md
DATE: 2025/1/23
WORDS: 329