如何在 AWS Step Functions 中的数组中使用 jsonPath
How to use jsonPath inside array in AWS Step Functions
我正在编写一个 AWS 步骤函数,对于其中一个步骤,我希望调用一个接受数组作为输入之一的 lambda。但是,如果我尝试将 JsonPath 传递到数组中,我会得到
The value for the field 'arrayField.$' must be a STRING that contains a JSONPath but was an ARRAY
我的步进函数定义:
{
"StartAt": "First",
"States": {
"First": {
"Type": "Pass",
"Parameters": {
"type": "person"
},
"ResultPath": "$.output",
"Next": "Second"
},
"Second": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:<aws_id>:function:MyFunction",
"Parameters": {
"regularParameter": "some string",
"arrayParameter.$": ["$.output.type"]
},
"Next": "Succeed"
},
"Succeed": {
"Type": "Succeed"
}
}
}
如何在数组中使用 jsonPath?
JSON参数字段中的路径必须是字符串。因此,如果你想向 lambda 函数传递一个名为 arrayParameter 的参数,你需要进行一个 jsonPath 查询来提取该数组。
例如,如果键输出中有一个名为 outputArray 的键,其值是数组。
输入JSON:
{
"pre": "sdigf",
"output": {
"result": 1,
"outputArray": ["test1","test2","test.."]
}
}
参数语法:
"arrayParameter.$": "$.output.outputArray"
合理建议
我今天 运行 研究了数组中 JsonPath 解析的一个用例,发现(就像你一样)这个功能今天不存在。我最终决定在代码中进行数据处理更简单、更清晰。例如,您可以创建一个小的 Lambda,它接收 First
发出的对象并将其处理为 Second
可接受的格式并将其添加到输出(WaterKnight 在 ).
假设您出于某种原因无法更改 Second
中 Lambda 的输入格式(这将是此处的绝对最短路径)。
不合理的建议
就是说,如果您想要一种完全在 Step Functions 中完成此操作的方法(相当粗糙),您可以使用 Map state that executes Pass states 的结果。 Map 状态的输出是一个数组,聚合了每个组成 Pass 状态的输出。这些 Pass 状态只是使用 Parameters
属性在最终数组中发出您想要的值。下面是一个示例 Step Function 定义。我确实警告说这很恶心,我用不同的方式解决了这个问题。
{
"StartAt": "First",
"Comment": "Please don't actually do this",
"States": {
"First": {
"Type": "Pass",
"Parameters": {
"type": "person"
},
"ResultPath": "$.output",
"Next": "Add Array"
},
"Add Array": {
"Comment": "A Map state needs some array to loop over in order to work. We will give it a dummy array. Add an entry for each value you intend to have in the final array. The values here don't matter.",
"Type": "Pass",
"Result": [
0
],
"ResultPath": "$.dummy",
"Next": "Mapper"
},
"Mapper": {
"Comment": "Add a Pass state with the appropriate Parameters for each field you want to map into the output array",
"Type": "Map",
"InputPath": "$",
"ItemsPath": "$.dummy",
"Parameters": {
"output.$": "$.output"
},
"Iterator": {
"StartAt": "Massage",
"States": {
"Massage": {
"Type": "Pass",
"Parameters": {
"type.$": "$.output.type"
},
"OutputPath": "$.type",
"End": true
}
}
},
"ResultPath": "$.output.typeArray",
"Next": "Second"
},
"Second": {
"Comment": "The Lambda in your example is replaced with Pass so that I could test this",
"Type": "Pass",
"Parameters": {
"regularParameter": "some string",
"arrayParameter.$": "$.output.typeArray"
},
"Next": "Succeed"
},
"Succeed": {
"Type": "Succeed"
}
}
}
正如@Seth Miller 所提到的,不幸的是,数组中的 JsonPath 解析不起作用。如果数组中要替换的值的数量很小并且已知有一个简单的解决方法(在我的例子中我需要一个大小为 1 的数组)。
步骤是:
- 用您需要的值的数量初始化数组;
- 使用
"ResultPath": "$.path.to.array[n]"
; 替换每个值
- 在你的任务中使用
"$.path.to.array"
。
简单有效的示例:
{
"StartAt": "First",
"States": {
"First": {
"Type": "Pass",
"Parameters": {
"type": "person"
},
"ResultPath": "$.output",
"Next": "Initialise Array"
},
"Initialise Array": {
"Comment": "Add an entry for each value you intend to have in the final array, the values here don't matter.",
"Type": "Pass",
"Parameters": [
0
],
"ResultPath": "$.arrayParameter",
"Next": "Fill Array"
},
"Fill Array": {
"Comment": "Replace the first entry of array with parameter",
"Type": "Pass",
"InputPath": "$.output.type",
"ResultPath": "$.arrayParameter[0]",
"End": true
}
}
}
并在您的任务示例中使用生成的数组:
"Second": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:<aws_id>:function:MyFunction",
"Parameters": {
"regularParameter": "some string",
"arrayParameter.$": "$.arrayParameter"
},
"Next": "Succeed"
},
正如许多答案正确指出的那样,不可能完全按照您需要的方式进行。但我会建议另一种解决方案:一系列字典。它不完全是您所需要的,但它是原生的而不是 hacky。
"Second": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:<aws_id>:function:MyFunction",
"Parameters": {
"regularParameter": "some string",
"arrayParameter": [{"type.$": "$.output.type"}]
},
"Next": "Succeed"
},
结果会是
{
"regularParameter": "some string",
"arrayParameter": [{"type": "SingleItemWrappedToAnArray"}]
}
解决此问题的另一种方法是使用输出对象数组的并行状态,然后使用 jsonPath 将其转换为简单数组:
{
"StartAt": "Parallel",
"States": {
"Parallel": {
"Type": "Parallel",
"Next": "Use Array",
"ResultPath": "$.items",
"Branches": [
{
"StartAt": "CreateArray",
"States": {
"CreateArray": {
"Type": "Pass",
"Parameters": {
"value": "your value"
},
"End": true
}
}
}
]
},
"Use Array": {
"Type": "Pass",
"Parameters": {
"items.$": "$.items[*].value"
},
"End": true
}
}
}
在此示例中,并行状态输出以下内容json:
{
"items": [
{
"value": "your value"
}
]
}
并且"Use Array"状态产生:
{
"items": [
"your value"
]
}
从新版本开始,您可以使用内部函数 States.Array
:
"arrayParameter.$": "States.Array($.output.type)"
https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-intrinsic-functions.html
我正在编写一个 AWS 步骤函数,对于其中一个步骤,我希望调用一个接受数组作为输入之一的 lambda。但是,如果我尝试将 JsonPath 传递到数组中,我会得到
The value for the field 'arrayField.$' must be a STRING that contains a JSONPath but was an ARRAY
我的步进函数定义:
{
"StartAt": "First",
"States": {
"First": {
"Type": "Pass",
"Parameters": {
"type": "person"
},
"ResultPath": "$.output",
"Next": "Second"
},
"Second": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:<aws_id>:function:MyFunction",
"Parameters": {
"regularParameter": "some string",
"arrayParameter.$": ["$.output.type"]
},
"Next": "Succeed"
},
"Succeed": {
"Type": "Succeed"
}
}
}
如何在数组中使用 jsonPath?
JSON参数字段中的路径必须是字符串。因此,如果你想向 lambda 函数传递一个名为 arrayParameter 的参数,你需要进行一个 jsonPath 查询来提取该数组。
例如,如果键输出中有一个名为 outputArray 的键,其值是数组。
输入JSON:
{
"pre": "sdigf",
"output": {
"result": 1,
"outputArray": ["test1","test2","test.."]
}
}
参数语法:
"arrayParameter.$": "$.output.outputArray"
合理建议
我今天 运行 研究了数组中 JsonPath 解析的一个用例,发现(就像你一样)这个功能今天不存在。我最终决定在代码中进行数据处理更简单、更清晰。例如,您可以创建一个小的 Lambda,它接收 First
发出的对象并将其处理为 Second
可接受的格式并将其添加到输出(WaterKnight 在
假设您出于某种原因无法更改 Second
中 Lambda 的输入格式(这将是此处的绝对最短路径)。
不合理的建议
就是说,如果您想要一种完全在 Step Functions 中完成此操作的方法(相当粗糙),您可以使用 Map state that executes Pass states 的结果。 Map 状态的输出是一个数组,聚合了每个组成 Pass 状态的输出。这些 Pass 状态只是使用 Parameters
属性在最终数组中发出您想要的值。下面是一个示例 Step Function 定义。我确实警告说这很恶心,我用不同的方式解决了这个问题。
{
"StartAt": "First",
"Comment": "Please don't actually do this",
"States": {
"First": {
"Type": "Pass",
"Parameters": {
"type": "person"
},
"ResultPath": "$.output",
"Next": "Add Array"
},
"Add Array": {
"Comment": "A Map state needs some array to loop over in order to work. We will give it a dummy array. Add an entry for each value you intend to have in the final array. The values here don't matter.",
"Type": "Pass",
"Result": [
0
],
"ResultPath": "$.dummy",
"Next": "Mapper"
},
"Mapper": {
"Comment": "Add a Pass state with the appropriate Parameters for each field you want to map into the output array",
"Type": "Map",
"InputPath": "$",
"ItemsPath": "$.dummy",
"Parameters": {
"output.$": "$.output"
},
"Iterator": {
"StartAt": "Massage",
"States": {
"Massage": {
"Type": "Pass",
"Parameters": {
"type.$": "$.output.type"
},
"OutputPath": "$.type",
"End": true
}
}
},
"ResultPath": "$.output.typeArray",
"Next": "Second"
},
"Second": {
"Comment": "The Lambda in your example is replaced with Pass so that I could test this",
"Type": "Pass",
"Parameters": {
"regularParameter": "some string",
"arrayParameter.$": "$.output.typeArray"
},
"Next": "Succeed"
},
"Succeed": {
"Type": "Succeed"
}
}
}
正如@Seth Miller 所提到的,不幸的是,数组中的 JsonPath 解析不起作用。如果数组中要替换的值的数量很小并且已知有一个简单的解决方法(在我的例子中我需要一个大小为 1 的数组)。
步骤是:
- 用您需要的值的数量初始化数组;
- 使用
"ResultPath": "$.path.to.array[n]"
; 替换每个值
- 在你的任务中使用
"$.path.to.array"
。
简单有效的示例:
{
"StartAt": "First",
"States": {
"First": {
"Type": "Pass",
"Parameters": {
"type": "person"
},
"ResultPath": "$.output",
"Next": "Initialise Array"
},
"Initialise Array": {
"Comment": "Add an entry for each value you intend to have in the final array, the values here don't matter.",
"Type": "Pass",
"Parameters": [
0
],
"ResultPath": "$.arrayParameter",
"Next": "Fill Array"
},
"Fill Array": {
"Comment": "Replace the first entry of array with parameter",
"Type": "Pass",
"InputPath": "$.output.type",
"ResultPath": "$.arrayParameter[0]",
"End": true
}
}
}
并在您的任务示例中使用生成的数组:
"Second": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:<aws_id>:function:MyFunction",
"Parameters": {
"regularParameter": "some string",
"arrayParameter.$": "$.arrayParameter"
},
"Next": "Succeed"
},
正如许多答案正确指出的那样,不可能完全按照您需要的方式进行。但我会建议另一种解决方案:一系列字典。它不完全是您所需要的,但它是原生的而不是 hacky。
"Second": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:<aws_id>:function:MyFunction",
"Parameters": {
"regularParameter": "some string",
"arrayParameter": [{"type.$": "$.output.type"}]
},
"Next": "Succeed"
},
结果会是
{
"regularParameter": "some string",
"arrayParameter": [{"type": "SingleItemWrappedToAnArray"}]
}
解决此问题的另一种方法是使用输出对象数组的并行状态,然后使用 jsonPath 将其转换为简单数组:
{
"StartAt": "Parallel",
"States": {
"Parallel": {
"Type": "Parallel",
"Next": "Use Array",
"ResultPath": "$.items",
"Branches": [
{
"StartAt": "CreateArray",
"States": {
"CreateArray": {
"Type": "Pass",
"Parameters": {
"value": "your value"
},
"End": true
}
}
}
]
},
"Use Array": {
"Type": "Pass",
"Parameters": {
"items.$": "$.items[*].value"
},
"End": true
}
}
}
在此示例中,并行状态输出以下内容json:
{
"items": [
{
"value": "your value"
}
]
}
并且"Use Array"状态产生:
{
"items": [
"your value"
]
}
从新版本开始,您可以使用内部函数 States.Array
:
"arrayParameter.$": "States.Array($.output.type)"
https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-intrinsic-functions.html