Getting Started with DynamoDB in Go (Part 3— Create, Read, Update and Delete an Item)

Miguel Cabrerizo
7 min readJan 24, 2018

In the third part of this tutorial for DynamoDB and Go, where I’m rewriting the Amazon AWS Node.js tutorial for the Go programming language, we’re going to see how to create, read, update and delete an item from our Movies table.

This post assumes you have a Movies table in your local DynamoDB instance and you have loaded the sample data from a JSON file.

In my suggested code I’m heavily using the marshal operations that AWS gives me to prepare expressions. In Go we could define an expression like this:

ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
“:r”: {
N: aws.String(“0.5”),
},
},

but I prefer to use the marshal operations, for example MarshalMap, to create the map[string]*dynamodb.AttributeValue, as I think the code is clearer and it’s easier to use the AttributeValues. You have plenty of alternative examples in Amazon AWS SDK for Go Examples page where the attribute values are defined as above if you prefer that way.

Step 3.1: Create a new item in our Movies table.

We’re going to add a new item representing a new movie:

{
year: 2015,
title: “The Big New Movie”,
info: {
plot: “Nothing happens at all.”,
rating: 0
}
}

This is the flow of actions:

  • We define a struct for the info and another struct for our movie.
  • We create a session for our DynamoDB local server and start a connection.
  • We use the utilities that AWS offers to marshal our movie, in this case we use the MarshalMap operation that takes our movie struct and prepares a map of attributevalues that we can use in the PutItem operation.
  • We prepare the input for the PutItem operation selecting the Movies table and adding the movie that was marshalled before as the item to be inserted.
  • We finally insert the new movie item.

Here’s the code for our main.go:

I run it

go run main.go

If the item is inserted we’ll see the following message

We have inserted a new item!

Step 3.2: Read an item

Now we’re going to read the item that we’ve just inserted. When we created the table we define two keys.

  • Year is our partition key.
  • Title is our sort key.

You may review the AWS DynamoDB core concepts article if you don’t remember what is a partition key and a sort key.

We’re going to use both keys to get the item from our table as it was a composite primary key.

Here’s the flow:

  • We define a struct for the movie to be retrieved. The type for the info field has been defined as interface{}, that way I can expect arbitrary data for the movie info. Also I define the info field to be omitted in the JSON object if it’s empty.
  • We create a session for our DynamoDB local server and start a connection.
  • We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside a GetItemInput struct.
  • We retrieve the item using the input.
  • We get a GetItemOutput that contains an Item field. We unmarshall the item using UmarshallMap and store the content in a Movie struct.
  • Note: the info field may contain arbitrary data so I can use the method described in the JSON and Go Blog post to retrieve data. If we know what is going to be inside the info field we could define a struct for the info and we could avoid that logic. I feel it was right for this tutorial assuming that we don’t know what’s inside the info field.

Here’s the code for our main.go

I run it again

go run main.go

And here’s the result

year: 2015
title: The Big New Movie
rating : 0
plot : Nothing happens at all.

Step 3.3: Update an Item

In this step we want to update the previous Item with the following information:

{
year: 2015,
title: “The Big New Movie”,
info: {
plot: “Everything happens all at once.”,
rating: 5.5,
actors: [“Larry”, “Moe”, “Curly”]
}
}

Here’s the flow:

  • We define a struct for the key of the movie item to be updated.
  • We define a struct that contains which fields are going to be updated. The struct contains json mappings with a name started with a colon, in AWS we use those tokens as placeholders for the info to be updated. For example rating will use :r and plot will use :p. You have more information in the API reference.
  • We also create two structs to be used when we unmarshal the data returned by the update operation.
  • We create a session for our DynamoDB local server and start a connection.
  • We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside an UpdateItemInput struct and is used to select which item must be updated.
  • We prepare a movieUpdate struct to be marshalled using MarshalMap. The marshalled update info will be added to an UpdateItemInput struct.
  • The UpdateItem operation requires the key for the item to be updated and the updated info. Also the UpdateExpression specifies what’s the mapping between the info fields and the tokens prefixed by a colon, similar to a SET clause in SQL. The ReturnValues set to UPDATED_NEW instructs DynamoDB to return only the values that have been updated.
  • The UpdateItem operation returns an UpdatedItemOutput which contains an Attributes field with the updated information. We use the UnmarshallMap operation using a MovieInfoUpdated struct to store the unmarshalled fields. Then we can print the new values.

Here’s the code for our main.go

And here’s the output for the updated info.

Updated plot: Everything happens all at once.
Updated rating: 5.5
Updated actors: [Larry Moe Curly]

Step 3.4: Increment an Atomic Counter

According to the Node.js tutorial, we are going to increment the rating for a movie using a counter.

Here’s the flow:

  • We define a struct for the key of the movie item to be updated.
  • We define a struct that contains the increment for the movie reating field. The struct contains a json mapping with a name started with a colon :val, in AWS we use those tokens as placeholders.
  • We also create two structs to be used when we unmarshal the data returned by the update operation.
  • We create a session for our DynamoDB local server and start a connection.
  • We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside an UpdateItemInput struct and is used to select which item must be updated.
  • We prepare a MovieRatingInc struct to be marshalled using MarshalMap with the number to be used in the increment operation.
  • The UpdateItem operation requires the key for the item to be updated and the updated info. Also the UpdateExpression specifies that rating is going to be incremented by the value we’ve set earlier.
  • The UpdateItem operation returns an UpdatedItemOutput which contains an Attributes field with the updated information. We use the UnmarshallMap operation using a MovieInfoUpdated struct to store the unmarshalled fields. Then we can print the new values.

Here’s the code for our main.go

And here’s the output for the updated info, ratings have been increased by 1.

Updated rating: 6.5

Step 3.5: Update an Item (Conditionally)

We’re going to update an item from our Movies table. If a movie has more than three actors we will remove the first actor, so we’re going to select a condition as we would use a WHERE clause in SQL.

Here’s the flow:

  • We define a struct for the key of the movie item to be updated.
  • We define a struct that contains which is the number of actors to be checked in the condition. The struct contains a json mapping with a name started with a colon :num, in AWS we use those tokens as placeholders.
  • We also create two structs to be used when we unmarshal the data returned by the update operation.
  • We create a session for our DynamoDB local server and start a connection.
  • We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside an UpdateItemInput struct and is used to select which item must be updated.
  • We prepare a MovieActorsCondition struct to be marshalled using MarshalMap with the number to be used when the number of actors in a movie is checked.
  • The UpdateItem operation requires the key for the item to be updated and the updated info. The UpdateExpression defines that we want to remove the first item in the actorrs array. The ConditionExpression specifies that the item will be updated only if the number of actors (size) is greater than 3.
  • The UpdateItem operation returns an UpdatedItemOutput which contains an Attributes field with the updated information. We use the UnmarshallMap operation using a MovieInfoUpdated struct to store the unmarshalled fields. Then we can print the new value.

Here’s the code:

When we run the code we’ll check that the condition fails as we have only three actors:

ConditionalCheckFailedException: The conditional request failed
status code: 400, request id: 3d6f2674–7de9–4a8c-ae6e-dfb98b49b691

We modify the main.go and change the condition, this time we’ll check size(info.actors) >= 3

Now when we run the code, we get the updated actors array where the first actor has been removed:

Actors updated: [Moe Curly]

Step 3.6: Delete an Item

In this final step we’re going to delete an Item if a condition is met. We’re going to delete an Item if the movie’s rating is lower than 5

Here’s the flow:

  • We define a struct for the key of the movie item to be updated.
  • We define a struct that contains which is the rating to be checked in the condition. The struct contains a json mapping with a name started with a colon :val, in AWS we use those tokens as placeholders.
  • We also create two structs to be used when we unmarshal the data returned by the update operation.
  • We create a session for our DynamoDB local server and start a connection.
  • We prepare a key struct to be marshalled using MarshalMap. The marshalled key is added to key field inside a DeletetemInput struct and is used to select which item must be removed.
  • We prepare a MovieRatingCondition struct to be marshalled using MarshalMap with the rating to be used in the condition.
  • The DeleteItem operation requires the key for the item to be deleted. The ConditionExpression specifies that the item will be removed only if the rating is lower than or equal to 5.0.

Here’s the code:

When we run the code our movie has a rating of 6.5 so it’s not deleted:

ConditionalCheckFailedException: The conditional request failed
status code: 400, request id: 07d86ea1–5d42–4016–9b7e-47a4b1fa0f82

If we change the condition so the movie is deleted if the rating is lower than 10, now the item will be deleted.

The item has been deleted

This concludes the third part of the tutorial. In the next part we’re going to query and scan the data.

--

--

Miguel Cabrerizo

Freelance DevOps practicioner who loves Docker, K8s, Typescript and Golang