In this step, we will create a new Mutation that allows updating an item in the DynamoDB table. We will use DynamoDB’s UpdateItem.
updatePost(
id: ID!,
author: String!,
title: String!,
content: String!,
url: String!
): Post



{
"version" : "2017-02-28",
"operation" : "UpdateItem",
"key" : {
"id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
},
"update" : {
"expression" : "SET author = :author, title = :title, content = :content, #url = :url ADD version :one",
"expressionNames": {
"#url" : "url"
},
"expressionValues": {
":author" : $util.dynamodb.toDynamoDBJson($context.arguments.author),
":title" : $util.dynamodb.toDynamoDBJson($context.arguments.title),
":content" : $util.dynamodb.toDynamoDBJson($context.arguments.content),
":url" : $util.dynamodb.toDynamoDBJson($context.arguments.url),
":one" : { "N": 1 }
}
}
}

This Resolver is using a DynamoDB UpdateItem, which is significantly different from a PutItem operation. Instead of writing the entire item, you are only asking DynamoDB to update certain attributes. To do this, you use DynamoDB Update Expressions. You can see the “expression” section under “update”. It tells DynamoDB to set the author, title, content, and url attributes, and then increment the version field. The Expression contains placeholders whose names begin with a colon, which are then defined in the “expressionValues” section. Finally, DynamoDB has reserved words that cannot appear in expressions. For example, url is a reserved word, so to update the url field, you can use placeholder names and define them in the “expressionNames” section.
#if($context.error)
$util.error($context.error.message, $context.error.type)
#end
$util.toJson($context.result)


mutation updatePost {
updatePost(
id:"123"
author: "A new author"
title: "An updated author!"
content: "Now with updated content!"
url: "https://aws.amazon.com/appsync/"
) {
id
author
title
content
url
ups
downs
version
}
}

{
"data": {
"updatePost": {
"id": "123",
"author": "A new author",
"title": "An updated author!",
"content": "Now with updated content!",
"url": "https://aws.amazon.com/appsync/",
"ups": 1,
"downs": 0,
"version": 2
}
}
}

After completing the update, the version attribute is incremented by one because we requested AWS AppSync and DynamoDB to add one to the version attribute upon each update.
When you use the updatePost mutation as above, two problems will occur:
updatePost(
id: ID!,
author: String,
title: String,
content: String,
url: String,
expectedVersion: Int!
): Post


{
"version" : "2017-02-28",
"operation" : "UpdateItem",
"key" : {
"id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
},
## Set up some space to keep track of things you're updating **
#set( $expNames = {} )
#set( $expValues = {} )
#set( $expSet = {} )
#set( $expAdd = {} )
#set( $expRemove = [] )
## Increment "version" by 1 **
$!{expAdd.put("version", ":one")}
$!{expValues.put(":one", { "N" : 1 })}
## Iterate through each argument, skipping "id" and "expectedVersion" **
#foreach( $entry in $context.arguments.entrySet() )
#if( $entry.key != "id" && $entry.key != "expectedVersion" )
#if( (!$entry.value) && ("$!{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}", { "S" : "${entry.value}" })}
#end
#end
#end
## Start building the update expression, starting with attributes you'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 you'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 you'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
## 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" : "version = :expectedVersion",
"expressionValues" : {
":expectedVersion" : $util.dynamodb.toDynamoDBJson($context.arguments.expectedVersion)
}
}
}

mutation updatePost {
updatePost(
id:123
title: "An empty story"
content: null
expectedVersion: 2
) {
id
author
title
content
url
ups
downs
version
}
}

{
"data": {
"updatePost": {
"id": "123",
"author": "A new author",
"title": "An empty story",
"content": null,
"url": "https://aws.amazon.com/appsync/",
"ups": 1,
"downs": 0,
"version": 3
}
}
}

In this request, we asked AWS AppSync and DynamoDB to only update the title and content fields, keeping the other fields the same except for incrementing the version field.

The request failed because the condition expression evaluated to false:
We will create two new mutations to update the ups and downs fields to record upvotes or downvotes for the post.
upvotePost(id: ID!): Post
downvotePost(id: ID!): Post
Then click Save Schema
Next, in the Resolvers pane on the right, find the upvotePost field of type Mutation, then select Attach

{
"version" : "2017-02-28",
"operation" : "UpdateItem",
"key" : {
"id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
},
"update" : {
"expression" : "ADD ups :plusOne, version :plusOne",
"expressionValues" : {
":plusOne" : { "N" : 1 }
}
}
}
#if($context.error)
$util.error($context.error.message, $context.error.type)
#end
$util.toJson($context.result)


{
"version" : "2017-02-28",
"operation" : "UpdateItem",
"key" : {
"id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
},
"update" : {
"expression" : "ADD downs :plusOne, version :plusOne",
"expressionValues" : {
":plusOne" : { "N" : 1 }
}
}
}
#if($context.error)
$util.error($context.error.message, $context.error.type)
#end
$util.toJson($context.result)

mutation votePost {
upvotePost(id:"123") {
id
author
title
content
url
ups
downs
version
}
}
{
"data": {
"upvotePost": {
"id": "123",
"author": "A new author",
"title": "An empty story",
"content": null,
"url": "https://aws.amazon.com/appsync/",
"ups": 2,
"downs": 0,
"version": 4
}
}
}

mutation votePost {
downvotePost(id:"123") {
id
author
title
content
url
ups
downs
version
}
}
