Appsync解析器条件更新AWSJSON属性

0

【以下的问题经过翻译处理】 我有一个用于对象的修改,在其中有多个非必填字段可能在单个调用中进行更新。其中一个属性"data"在架构中被定义为AWSJSON。为了构建更新,我使用以下类似的语句来检查提供的值#if( !$util.isNull(${context.arguments.input.data}) )

如果存在属性的数据,那么必要的值将被添加到映射中,以构建最终的SET表达式,映射属性名称#data => data(对于具有保留字名称的属性是必要的),以及values :data => value

最终的更新使用$utils.toJson来应用构建的映射。问题是,当我提供AWSJSON属性的数据时,我收到以下错误: "Expected JSON object for attribute value '$[update][expressionValues][:data]' but got 'STRING' instead."

只要没有提供JSON属性,所有其他属性都可以正常工作。

然而,如果我改为内联提供expressionValues,而不是使用$utils.toJson,但也不能有条件地添加属性到更新中,它会按预期工作。我是否使用了错误的方式将收集的expressionValues映射应用于最终的更新语句,也许应该使用不同的$utils方法?还有其他解决方法来处理变化的非必填属性的集合吗?最坏的情况下,我可以为JSON属性创建一个单独的变化,但显然不是理想的方法,因为需要两次调用而不是一次。

我可以像这样从Appsync控制台进行调用:

mutation UpdateMyItem {
  updateMyItem(input: {
    id: "ITEM-ID-HERE",
    data:"[{\"xyz\": 101}]"
  }) {
    id,
    data
  }
}

解析:

{
  "version": "2017-02-28",
  "operation" : "UpdateItem",
  "key" : {
    "id" : $util.dynamodb.toDynamoDBJson($context.arguments.input.id)
  },
  ## Set up some space to keep track of things we're updating **
  #set( $expSet = {} )
  #set( $expNames = {} )
  #set( $expValues = {} )

  ## updatedAt
  #set($now = $util.time.nowISO8601())
  $!{expSet.put("updatedAt", ":updatedAt")}
  $!{expValues.put(":updatedAt", { "S" : "$now"})}

  ## data
  #if( !$util.isNull(${context.arguments.input.data}) )
    $!{expSet.put("#data", ":data")}
    $!{expNames.put("#data", "data")}
    $!{expValues.put(":data", $util.dynamodb.toDynamoDBJson($context.arguments.input.data) )}
  #end

  ## other redacted optional input arguments of various types would be here

  ## build the expression
  #set( $expression = "SET" )
  #foreach( $entry in $expSet.entrySet() )
    #set( $expression = "${expression} ${entry.key} = ${entry.value}" )
    #if ( $foreach.hasNext )
      #set( $expression = "${expression}," )
    #end
  #end

  "update" : {
    "expression": "${expression}",
    "expressionNames": $utils.toJson($expNames),
    ## this fails and results in an error: 
    ## "Expected JSON object for attribute value '$[update][expressionValues][:data]' but got 'STRING' instead."
    "expressionValues": $util.toJson( $expValues )
    ## this works and all attributes are updated
    ##"expressionValues": {
    ##  ":updatedAt" : $util.dynamodb.toDynamoDBJson($now),
    ##  ":data" : $util.dynamodb.toDynamoDBJson($context.arguments.input.data)
    ##}
  }
}
profile picture
专家
已提问 5 个月前19 查看次数
1 回答
0

【以下的回答经过翻译处理】 我支持你,你的方向是对的

$!{expValues.put(":data", $util.dynamodb.toDynamoDBJson($context.arguments.input.data) )}

$!{expValues.put(":data", $util.dynamodb.toDynamoDB($context.arguments.input.data) )}

如果您使用控制台解析器测试器按原样运行您的解析器代码,您会注意到您的代码的输出是:

...
"expressionValues": {
  ":updatedAt": { "S": "2019-07-10T20:35:30.000Z" },
  ":data": "{\"S\":\"[{\\\"xyz\\\": 101}]\"}"
}
...
...
"expressionValues": {
  ":updatedAt": { "S": "2019-07-10T20:35:30.000Z" },
  ":data": "{\"S\":\"[{\\\"xyz\\\": 101}]\"}"
}
...

您会注意到这里的区别是":updatedAt"键打印了一个DynamoDB类型的对象。(参见:<https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference- dynamodb.html#aws-appsync-resolver-mapping-template-reference-dynamodb-typed-values-request>),而":data"键打印了一个DynamoDB类型的对象,但作为一个字符串。这就是为什么您收到了"Expecting JSON object..."错误的原因,因为DynamoDB解析器期望一个JSON对象来指定要写入DynamoDB的值的类型。


如果您查看 DynamoDB Resolver Util 参考(参见:<https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html#dynamodb-helpers-in-util-dynamodb>) ,您会注意到`$util.dynamodb.toDynamoDBJson(Object)`方法返回一个字符串,您将其保存到`expValues`映射中,然后传递给`$util.toJson(Object)`,后者期望一个输入对象,并将其作为字符串返回,然后在vtl中打印为输出。我理解这可能会令人困惑,因为这里涉及了几个层次:您如何将值存储在`expValues`映射中,以及所有变量都必须评估为字符串,以便作为VTL的输出打印(总体上是一个字符串,用于表示DynamoDB数据源理解的JSON对象。

进一步查看解析器参考,您会看到`$util.dynamodb.toDynamoDB(Object)`方法,它返回一个Map,与您在":updatedAt"中定义的字面上的映射相同,即`{ "S": "$now" }`,这将为您提供预期的输出,将打印在`expressionValues`下。
profile picture
专家
已回答 5 个月前

您未登录。 登录 发布回答。

一个好的回答可以清楚地解答问题和提供建设性反馈,并能促进提问者的职业发展。

回答问题的准则