Inserting, Updating, and Querying items using the DynamoDB node.js documentclient

Chris Biscardi
InstructorChris Biscardi

Share this video with your friends

Send Tweet
Published 2 years ago
Updated 2 years ago

We use the node.js DynamoDB document client from the aws-sdk package, along with the uuid package, to insert, update, and query items in DynamoDB. We also cover related topics like reserved words in queries and how to get around that, KeyConditionExpressions like begins_with, and other extras on the way.

Instructor: [0:00] Back in our app we'll go into the old Fauna test directory that we used to have, and we'll rename it. Note that our [inaudible] file still contains Fauna and will get rid of all of our Fauna experimentation.

[0:12] We're going to replace our old Fauna experimentation with our new AWS experimentation. Note that we'll need the AWS SDK and the UUID package for this.

[0:29] Now that we have the necessary packages installed, we can go through the rest of our code. First, we need to update the AWS config with the region that our DynamoDB database is deployed in, as well as the access key and the secret access token. We'll get to these in a second.

[0:44] We've put the name of our table in a constant because we'll be querying this table. If we're going to query an index, we would have to use that identifier as well. We haven't created any indexes yet, so we don't have to worry about that.

[0:55] Next, we'll instantiate a document client using AWS.DynamoDB.DocumentClient. This is a high-level client for the Dynamo DB database. We've set up the parameters for our query using a constant. The table name be the table that we're storing our todos in.

[1:10] When we run a put, which is the operation that will run on doc client in certain object, we need to give it an item. This item is a JSON representation of all of the values in our attributes.

[1:22] Like I said before, the document client is a high-level client which means that we don't have to deal with any of the low-level types like S or N. We can interact with the API using just an object.

[1:33] If we try to run the script currently, we end up with a requested resource not found exception. This is because we haven't included our access key or our secret key yet. From the AWS console, you can go up to the right, click on our name and go to My Security Credentials. If we go to access keys, we can see a warning.

[1:53] Since it's the original account we created when we signed up for AWS, it's considered our root user account. In this case, it's the easiest way to get an access key ID and a secret access key that will get us access to the DynamoDB table.

[2:08] It also gives us access to literally everything else in our AWS account. You want to make sure that when you create these access keys, that you keep them in a safe place, you don't commit them to git, and you don't show them to anybody.

[2:19] In the future, when we switch over to Serverless Framework, we'll take the approach of creating new IM roles and giving our Lambdas specific privileges so that they can only access a specific table rather than our entire account. For now, let's go ahead and create a new access key. You can choose to download the key file or show it.

[2:38] Once you've put the AWS access key ID and the AWS secret access key into the environment or your preferred method, we run the script again. You can still see a "Resource not found exception: Requested resource not found." This is because our DynamoDB table is actually not a us-east-1.

[2:58] We look at tables. When we look at the top right and the regions dropdown, we can see that us-east-1 is in North Virginia. We click on North Virginia. We can see that there's no DynamoDB tables there. We click back on us-east-2, which is Ohio, we can see our table.

[3:15] If we run the script, we can see that the result is an empty object. If we check our table, we can see that user#1 with a todo of a UUID was inserted. We can see when it was created and whether it's done or not. Let's create a couple more todos. Note that you'll have to refresh the console page to see the additional todos. It does not update automatically.

[3:37] We can see that we have a couple of todos here. Note that we've forgotten to include text in our data. Text is a fairly critical part of a todo, because otherwise we don't have anything to display. If we look at one of these todos specifically, we can get the SK for that todo. This is going to be critical for updating this todo with an additional field in the data map.

[3:58] Note that because DynamoDB doesn't have a schema, we can do whatever we want with this data, which includes adding the new todo text. In this case, we're going to use docClient.update with the params that we pass it. Remember to use the promise on the end to make this a promise that we can await. Otherwise, this function takes a callback.

[4:16] We set the PK and SK in key. That gives us the primary key for the item that we're going to update. We're going to set a value called text equal to :newText using an UpdateExpression. Note that this syntax with a colon before the text for a value that we're setting needs to be replaced in the string with the content. This is similar to what you might do for a prepared query for a SQL query.

[4:43] We run this. We get a new error. Validation exception: Invalid UpdateExpression. The UpdateExpression is this expression here on the left. Attribute name is a reserved keyword text. Text is a reserved keyword, but this is OK because what we need here is data.text.

[5:06] Note that the same thing has happened again. In this case, the UpdateExpression is failing on the reserved keyword data. There are quite a few reserved keywords in DynamoDB. Though it's usually better to treat everything as a replaceable value rather than just setting some values that we think might be reserved.

[5:24] We can use a hash at the beginning of data to tell the Dynamo document client that this is a replaceable value. We will also have to use different map, which is expression attribute names, rather than expression attribute values.

[5:39] If we run this again, we can see that even though we've moved to where text is, it's still a reserved word. We'll add it to the attribute names and run again. You can see that we've got nothing back. We refresh the page and check our todo again.

[5:53] You can see that the text "My first todo" has been added to the data map. This flexibility and being able to add or remove any keys is extremely useful when you're working with DynamoDB. Note that the only field we can't do this for is the PK, or partition key.

[6:09] To change the partition key, we would need to delete this item entirely and recreate it well. We'll update the other todos while we're here as well. This gives us two of the queries we need. The first one being inserting a todo, and the second one being updating a todo. Let's change this to update the done field instead of the text field.

[6:29] Note that in this case, I'll set data.done, the new done, and new done will be true. If we look at our third todo, we can see that the text says, "My second todo," because we didn't change that, which we can change in the console right here right now. The done field is true, just like we updated. We'll save that modification.

[6:51] Finally, we need to query and get back a list of all the todos. We'll set the table name, and we'll set the key condition expression. Note that we're setting the key condition expression to do an exact match on the PK, which is the user ID, and we're checking the SK to see if it begins with something.

[7:09] We'll set our user ID to User1, and we'll set what we're searching for for the prefix todo with the #. Now when we run our script, we get back a list of items, which are User1 todo and the data. We also get back the count and the scans count. These are numbers that inform us how many results we have and how many we looked at before we got them back.

[7:31] We stringify this and we look at the resulting data. We can see that we've got User1 with a todo ID created at a time. Not done yet with My first todo. We've got another todo that's not done yet. That's My second todo. My third todo is done.