Saving an order
DynamoDB is a cloud database that stores records, called items, in tables. Shops and apps use it to save orders and find them again in milliseconds.
Unlike a spreadsheet, every value in a DynamoDB item says what type it is. Your Python code has to read and write those typed values.
By the end of this lesson
Note
I can read and write a DynamoDB item in its typed form.
Key words
| Word | What it means | Example |
|---|---|---|
| Table | a named collection of items | |
| Item | one record in a table | |
| Attribute | a named value inside an item | |
| Type letter | the code that says what kind of value it is | S |
| String set | a group of different strings with no order |
The cells students fill in are left blank in this preview.
Every value carries its type letter
A DynamoDB table holds items. An item is a set of attributes, each with a name and a value.
The value is a dictionary with one key, a type letter, such as {"S": "tea"}. S is a string and N is a number. BOOL is true or false, and NULL is no value.
Worked example: the type letters
| Letter | Holds | Example |
|---|---|---|
| S | a string | {"S": "tea"} |
| N | a number, written as text | {"N": "4"} |
| BOOL | true or false | {"BOOL": false} |
| NULL | no value | {"NULL": true} |
| SS | a string set, in no fixed order | {"SS": ["rush", "fragile"]} |
The cells students fill in are left blank in this preview.
Run it: read an item
answer = {
"Item": {
"customer": {"S": "ana"},
"gift": {"BOOL": False},
"item": {"S": "tea"},
"note": {"NULL": True},
"order_id": {"N": "1"},
"status": {"S": "paid"},
"tags": {"SS": ["rush", "fragile"]},
"total": {"N": "4"},
}
}
item = answer["Item"]
for name in item:
kind = list(item[name].keys())[0]
print(name, "has type", kind)
print("item:", item["item"]["S"])
# Add a line that prints the status.
A number travels as text
DynamoDB sends every number as a string, such as {"N": "15"}, so that every digit arrives as written.
To use one, convert it with int("15") or float("2.5"). To store one, turn it back into text with str.
Worked example: using a number
| Step | Python | Result |
|---|---|---|
| Read | total["N"] | "15" |
| Convert | int(total["N"]) | 15 |
| Add one | int(total["N"]) + 1 | 16 |
| Write back | {"N": str(16)} | {"N": "16"} |
The cells students fill in are left blank in this preview.
Run it: text against number
total = {"N": "15"}
print(total["N"] + "1")
print(int(total["N"]) + 1)
print("9" > "15", 9 > 15)
print({"N": str(16)})
# Change "15" to "40". What does each line print now?
A common mistake
Warning
Many people think Python reads {"N": "15"} as the number 15. In Python it is the text "15". Adding to it joins text, so "15" + "1" gives "151". Convert with int or float before any sum, and use str to write it back.
A missing item is an empty answer
Asking for an item that does not exist is not an error. get_item answers with no Item key at all.
A write with a condition, such as "only if this order is new", can be refused. The error has the Code ConditionalCheckFailedException and status 400. The captured file writes it as {"error": ...}. boto3 raises an exception that carries the same Code and status.
Run it: found, missing and refused
found = {"Item": {"customer": {"S": "ana"}, "note": {"NULL": True}}}
missing = {}
refused = {"error": {"Code": "ConditionalCheckFailedException", "HTTPStatusCode": 400}}
for answer in [found, missing]:
if "Item" in answer:
print("found, note is null:", answer["Item"]["note"]["NULL"])
else:
print("no such item")
print(refused["error"]["Code"], refused["error"]["HTTPStatusCode"])
# Change the note to {"S": "gift card"}, then read it with ["S"].
Try it in the cloud lab
The cloud lab is a practice copy of S3, SQS and DynamoDB. Press Start the lab on the bar, then press Run on each command below. They use the real AWS command line, so the same words work on a real account. The last command prints nothing: a missing item is an empty answer here, not an error. This step is for practice. The assignment below stays plain Python, so you can do it without the lab.
Set a made-up key and the lab's address
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 AWS_ENDPOINT_URL=http://cloud:4566Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Make a table
aws dynamodb create-table --table-name Orders --attribute-definitions AttributeName=customer,AttributeType=S AttributeName=order,AttributeType=S --key-schema AttributeName=customer,KeyType=HASH AttributeName=order,KeyType=RANGE --billing-mode PAY_PER_REQUEST --query TableDescription.TableStatusShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Put an item
aws dynamodb put-item --table-name Orders --item '{"customer":{"S":"ada"},"order":{"S":"1001"},"total":{"N":"12"}}'Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Get the item
aws dynamodb get-item --table-name Orders --key '{"customer":{"S":"ada"},"order":{"S":"1001"}}'Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Get an item that is not there
aws dynamodb get-item --table-name Orders --key '{"customer":{"S":"ada"},"order":{"S":"9999"}}'Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.