Search code examples
amazon-web-servicesaws-step-functions

Syntax tuning of the ResultSelector to extract proper output from Step Functions state machine


I have a state machine with a single map state that iterate across an array of 2 elements whose output is this:

[
  {
    "BillingDetails": {
      "BilledDurationInMilliseconds": 100,
      "BilledMemoryUsedInMB": 64
    },
    "ExecutionArn": "arn:aws:states:us-west-2:693935722839:express:restaurantdbread:53054495-6e74-47bb-b58e-ad1f40b8282e:255e2717-5126-422a-81e4-b13e505a2f16",
    "Input": "{\"restaurant_name\":\"outback\"}",
    "InputDetails": {
      "Included": true
    },
    "Name": "53054495-6e74-47bb-b58e-ad1f40b8282e",
    "Output": "\"27\"",
    "OutputDetails": {
      "Included": true
    },
    "StartDate": "2022-11-17T08:47:30.364Z",
    "StateMachineArn": "arn:aws:states:us-west-2:693935722839:stateMachine:restaurantdbread",
    "Status": "SUCCEEDED",
    "StopDate": "2022-11-17T08:47:30.435Z"
  },
  {
    "BillingDetails": {
      "BilledDurationInMilliseconds": 100,
      "BilledMemoryUsedInMB": 64
    },
    "ExecutionArn": "arn:aws:states:us-west-2:693935722839:express:restaurantdbread:7d1597ea-973a-41ac-bf16-f506dd745566:f72ecfc1-93fc-47aa-a494-e925f9c95214",
    "Input": "{\"restaurant_name\":\"ihop\"}",
    "InputDetails": {
      "Included": true
    },
    "Name": "7d1597ea-973a-41ac-bf16-f506dd745566",
    "Output": "\"0\"",
    "OutputDetails": {
      "Included": true
    },
    "StartDate": "2022-11-17T08:47:30.366Z",
    "StateMachineArn": "arn:aws:states:us-west-2:693935722839:stateMachine:restaurantdbread",
    "Status": "SUCCEEDED",
    "StopDate": "2022-11-17T08:47:30.437Z"
  }
]

I need to compose an output that looks like:

[{"name": "outback", "value": 27}, {"name": "chipotle", "value": 0}]

I am adding to my state machine the following ResultSelector:

            "ResultSelector": {
                "name.$": "States.StringToJson($.Input)", 
                "value.$": "States.StringToJson($.Output)"
            },

Now I am getting something that is close to what I need:

[
  {
    "name": {
      "restaurant_name": "outback"
    },
    "value": "27"
  },
  {
    "name": {
      "restaurant_name": "ihop"
    },
    "value": "0"
  }
]

I am struggling to tune the output so that the "restaurant_name": get discarded to achieve the desired format.

I tried to tweak the ResultSelector to use:

            "ResultSelector": {
                "name.$": "States.StringToJson($.Input.restaurant_name)", 
                "value.$": "States.StringToJson($.Output)"
            },

But the workflow spits this error:

The function 'States.StringToJson($.Input.restaurant_name)' had the following error: The JsonPath argument for the field '$.Input.restaurant_name' could not be found in the input '{"BillingDetails":{"BilledDurationInMilliseconds":100,"BilledMemoryUsedInMB":64},"ExecutionArn":"arn:aws:states:us-west-2:693935722839:express:restaurantdbread:b8e9de51-1806-47ab-b4e6-1c60d6cd9fc1:9ce2cb9d-0b57-4066-b7de-a41668d6113f","Input":"{\"restaurant_name\":\"ihop\"}","InputDetails":{"Included":true},"Name":"b8e9de51-1806-47ab-b4e6-1c60d6cd9fc1","Output":"\"0\"","OutputDetails":{"Included":true},"StartDate":"2022-11-17T08:58:44.627Z","StateMachineArn":"arn:aws:states:us-west-2:693935722839:stateMachine:restaurantdbread","Status":"SUCCEEDED","StopDate":"2022-11-17T08:58:44.686Z"}'

Any suggestion on what syntax to use to only extract the name of the restaurant?


Solution

  • I was able to solve (or workaround) my problem by adding a new map state which decomposes the array in input and apply a Parameters to the Pass task. This is what the additional state looks like:

        "Map formatting": {
          "Type": "Map",
          "End": true,
          "Iterator": {
            "StartAt": "Pass",
            "States": {
              "Pass": {
                "Type": "Pass",
                "End": true,
                "Parameters": {
                  "name.$": "$.name.restaurant_name",
                  "value.$": "$.value"
                }
              }
            }
          }
        }
    

    This may not be the most efficient way to achieve what I need (I may not need two separate maps to construct the output required) but right now I am focused more on the basic functionality to work than on an optimized workflow so it works for me.