Amazon web services Automated DynamoDB createdAt、updatedAt和;使用解析器的版本属性

Amazon web services Automated DynamoDB createdAt、updatedAt和;使用解析器的版本属性,amazon-web-services,amazon-dynamodb,aws-appsync,vtl,Amazon Web Services,Amazon Dynamodb,Aws Appsync,Vtl,我第一次使用AWS AppSync并试图理解DynamoDB解析器。我的模式包括三个我希望自动设置的元数据属性:createdAt:awstiestamp,updatedAt:awstiestamp,以及version:Integer。我能够在creatItemresolver中设置它们的初始值,但是我在理解updateItemresolver的工作原理时遇到了困难 供参考,这些都位于AWS上类似的URL: 经过多次尝试和错误,我现在的代码如下: ##Update versioning a

我第一次使用AWS AppSync并试图理解DynamoDB解析器。我的模式包括三个我希望自动设置的元数据属性:
createdAt:awstiestamp
updatedAt:awstiestamp
,以及
version:Integer
。我能够在
creatItem
resolver中设置它们的初始值,但是我在理解
updateItem
resolver的工作原理时遇到了困难

供参考,这些都位于AWS上类似的URL:

经过多次尝试和错误,我现在的代码如下:

  ##Update versioning attributes
  #if( !${expNames.isEmpty()} )
    $!{expSet.put("#updatedAt", ":updatedAt")}
    $!{expNames.put("#updatedAt", "updatedAt")}
    $!{expValues.put(":updatedAt", $util.dynamodb.toDynamoDB($util.time.nowEpochMilliSeconds() ))}

    $!{expSet.put("#version", ":version")}
    $!{expNames.put("#version", "version")}
    $!{expValues.put(":version", $util.dynamodb.toNumber(99))}
  #end
下面是当前的错误:

{
  "data": {
    "updateItem": null
  },
  "errors": [
    {
      "path": [
        "updateItem"
      ],
      "data": null,
      "errorType": "DynamoDB:AmazonDynamoDBException",
      "errorInfo": null,
      "locations": [
        {
          "line": 74,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "Value provided in ExpressionAttributeNames unused in expressions: keys: {#updatedAt, #version} (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: YADDAYADDAYADDA)"
    }
  ]
}
您还会注意到,我将version设置为静态值99,而不是
n+1
。这是我下一步要解决的问题,但如果你有任何建议,我很乐意在这里提供

这是完整的分解器,包括所有AWS的锅炉板:

{
  "version": "2017-02-28",
  "operation": "UpdateItem",
  "key": {
    "id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id),
  },

  ## Set up some space to keep track of things we're updating **
  #set( $expNames  = {} )
  #set( $expValues = {} )
  #set( $expSet = {} )
  #set( $expAdd = {} )
  #set( $expRemove = [] )

  ## Iterate through each argument, skipping keys **
  #foreach( $entry in $util.map.copyAndRemoveAllKeys($ctx.args.input, ["id"]).entrySet() )
    #if( $util.isNull($entry.value) )
      ## If the argument is set to "null", then remove that attribute from the item in DynamoDB **

      #set( $discard = ${expRemove.add("#${entry.key}")} )
      $!{expNames.put("#${entry.key}", "${entry.key}")}
    #else
      ## Otherwise set (or update) the attribute on the item in DynamoDB **

      $!{expSet.put("#${entry.key}", ":${entry.key}")}
      $!{expNames.put("#${entry.key}", "${entry.key}")}
      $!{expValues.put(":${entry.key}", $util.dynamodb.toDynamoDB($entry.value))}
    #end
  #end

  ## Start building the update expression, starting with attributes we're going to SET **
  #set( $expression = "" )
  #if( !${expSet.isEmpty()} )
    #set( $expression = "SET" )
    #foreach( $entry in $expSet.entrySet() )
      #set( $expression = "${expression} ${entry.key} = ${entry.value}" )
      #if ( $foreach.hasNext )
        #set( $expression = "${expression}," )
      #end
    #end
  #end

  ## Continue building the update expression, adding attributes we're going to ADD **
  #if( !${expAdd.isEmpty()} )
    #set( $expression = "${expression} ADD" )
    #foreach( $entry in $expAdd.entrySet() )
      #set( $expression = "${expression} ${entry.key} ${entry.value}" )
      #if ( $foreach.hasNext )
        #set( $expression = "${expression}," )
      #end
    #end
  #end

  ## Continue building the update expression, adding attributes we're going to REMOVE **
  #if( !${expRemove.isEmpty()} )
    #set( $expression = "${expression} REMOVE" )

    #foreach( $entry in $expRemove )
      #set( $expression = "${expression} ${entry}" )
      #if ( $foreach.hasNext )
        #set( $expression = "${expression}," )
      #end
    #end
  #end



  ##Update versioning attributes
  #if( !${expNames.isEmpty()} )
    $!{expSet.put("#updatedAt", ":updatedAt")}
    $!{expNames.put("#updatedAt", "updatedAt")}
    $!{expValues.put(":updatedAt", $util.dynamodb.toDynamoDB($util.time.nowEpochMilliSeconds() ))}

    $!{expSet.put("#version", ":version")}
    $!{expNames.put("#version", "version")}
    $!{expValues.put(":version", $util.dynamodb.toNumber(99))}
  #end

  ## Finally, write the update expression into the document, along with any expressionNames and expressionValues **
  "update": {
    "expression": "${expression}",
    #if( !${expNames.isEmpty()} )
      "expressionNames": $utils.toJson($expNames),
    #end
    #if( !${expValues.isEmpty()} )
      "expressionValues": $utils.toJson($expValues),
    #end
  },

  "condition": {
    "expression": "attribute_exists(#id)",
    "expressionNames": {
      "#id": "id",
    },
  }
}
提前谢谢

Edit:我试图概括上面的表名,但实际的模式如下所示:

input CreateMapInput {
    title: String!
    imageUrl: AWSURL!
    center: AWSJSON
    zoom: Float
    bearing: Float
    imageType: String
    sourceSize: AWSJSON
    cropSize: AWSJSON
    cropAnchor: AWSJSON
    corners: AWSJSON
    country: String
    city: String
    published: Boolean
}

input DeleteMapInput {
    id: ID!
}

type Map {
    id: ID!
    title: String!
    imageUrl: AWSURL!
    center: AWSJSON
    zoom: Float
    bearing: Float
    imageType: String
    sourceSize: AWSJSON
    cropSize: AWSJSON
    cropAnchor: AWSJSON
    corners: AWSJSON
    country: String
    city: String
    published: Boolean
    createdAt: AWSTimestamp
    updatedAt: AWSTimestamp
version: Int
}

type MapConnection {
    items: [Map]
    nextToken: String
}

type Mutation {
    createMap(input: CreateMapInput!): Map
    updateMap(input: UpdateMapInput!): Map
    deleteMap(input: DeleteMapInput!): Map
}

type Query {
    getMap(id: ID!): Map
    listMaps(filter: TableMapFilterInput, limit: Int, nextToken: String): MapConnection
}

type Subscription {
    onCreateMap(
        id: ID,
        title: String,
        imageUrl: AWSURL,
        center: AWSJSON,
        zoom: Float
    ): Map
        @aws_subscribe(mutations: ["createMap"])
    onUpdateMap(
        id: ID,
        title: String,
        imageUrl: AWSURL,
        center: AWSJSON,
        zoom: Float
    ): Map
        @aws_subscribe(mutations: ["updateMap"])
    onDeleteMap(
        id: ID,
        title: String,
        imageUrl: AWSURL,
        center: AWSJSON,
        zoom: Float
    ): Map
        @aws_subscribe(mutations: ["deleteMap"])
}

input TableBooleanFilterInput {
    ne: Boolean
    eq: Boolean
}

input TableFloatFilterInput {
    ne: Float
    eq: Float
    le: Float
    lt: Float
    ge: Float
    gt: Float
    contains: Float
    notContains: Float
    between: [Float]
}

input TableIDFilterInput {
    ne: ID
    eq: ID
    le: ID
    lt: ID
    ge: ID
    gt: ID
    contains: ID
    notContains: ID
    between: [ID]
    beginsWith: ID
}

input TableIntFilterInput {
    ne: Int
    eq: Int
    le: Int
    lt: Int
    ge: Int
    gt: Int
    contains: Int
    notContains: Int
    between: [Int]
}

input TableMapFilterInput {
    id: TableIDFilterInput
    title: TableStringFilterInput
    imageUrl: TableStringFilterInput
    zoom: TableFloatFilterInput
    bearing: TableFloatFilterInput
    imageType: TableStringFilterInput
    country: TableStringFilterInput
    city: TableStringFilterInput
    published: TableBooleanFilterInput
    createdAt: TableIntFilterInput
    updatedAt: TableIntFilterInput
    version: TableIntFilterInput
}

input TableStringFilterInput {
    ne: String
    eq: String
    le: String
    lt: String
    ge: String
    gt: String
    contains: String
    notContains: String
    between: [String]
    beginsWith: String
}

input UpdateMapInput {
    id: ID!
    title: String
    imageUrl: AWSURL
    center: AWSJSON
    zoom: Float
    bearing: Float
    imageType: String
    sourceSize: AWSJSON
    cropSize: AWSJSON
    cropAnchor: AWSJSON
    corners: AWSJSON
    country: String
    city: String
    published: Boolean
}
还有,查询和变量:

mutation updateMap($updatemapinput: UpdateMapInput!) {
  updateMap(input: $updatemapinput) {
    id
    title
    imageUrl
    center
    zoom
    bearing
    imageType
    sourceSize
    cropSize
    cropAnchor
    corners
    country
    city
    published
    createdAt
    updatedAt
    version
  }
}

这里的问题是,您没有使用正在设置的属性更新表达式变量

如果您将代码更新为此,它应该可以工作

##Update versioning attributes
  #if( !${expNames.isEmpty()} )
    #set( $expression = "${expression}, SET updatedAt = $util.time.nowEpochMilliSeconds()" )
    $!{expSet.put("#updatedAt", ":updatedAt")}
    $!{expNames.put("#updatedAt", "updatedAt")}
    $!{expValues.put(":updatedAt", $util.dynamodb.toDynamoDB($util.time.nowEpochMilliSeconds() ))}

    #set( $expression = "${expression}, SET version = $util.dynamodb.toNumber(99)" )
    $!{expSet.put("#version", ":version")}
    $!{expNames.put("#version", "version")}
    $!{expValues.put(":version", $util.dynamodb.toNumber(99))}
  #end
我建议的另一个选项是在模板开头的输入中插入值,这样,就不必更新表达式变量。可以通过这种方式实现前面的目标

#set($ctx.args.input['updatedAt'] = $util.time.nowEpochMilliSeconds())
#set($ctx.args.input['version'] = 99)

并且您必须删除添加到模板中的“##更新版本控制属性”代码部分。

能否提供用于更新记录的graphQL模式和变体?添加,@Neill。如果你有任何建议,请告诉我。谢谢,我使用了你的第二个建议。关于如何增加
version
而不是将其设置为静态值(例如99)的任何指针?
#set($ctx.args.input['updatedAt'] = $util.time.nowEpochMilliSeconds())
#set($ctx.args.input['version'] = 99)