Expressions are how you modify, protect and trim items, and the syntax trips everyone up at first.
DynamoDB uses small expression languages instead of SQL.
An UpdateExpression has up to four clauses, each used once:
SET a = :v, b = b + :one, c = if_not_exists(c, :zero), l = list_append(l, :new)REMOVE attr, list[0]deletes attributes or list elementsADD counter :nincrements a number (creating it at 0 if missing) or adds to a setDELETE tags :oldremoves elements from a set
Nested paths use dots and indexes: address.city, items[2].qty.
Values are never written inline. Use placeholders: :name for values in ExpressionAttributeValues, and #name in ExpressionAttributeNames for attribute names that are reserved words (status, name, date, count and hundreds more) or contain special characters.
A ConditionExpression uses comparisons, AND/OR/NOT, BETWEEN, IN, and functions like attribute_exists(a), attribute_not_exists(a), begins_with, contains, size. A ProjectionExpression lists attributes to return. In boto3 the resource layer lets you write conditions with Attr("x").gt(1) objects instead of strings.
ADD and SET x = x + :n are atomic increments: safe under concurrency without reading first.
Example
import boto3
table = boto3.resource("dynamodb").Table("Orders")
key = {"customer_id": "c9", "order_id": "o1"}
table.put_item(Item={**key, "tags": {"new"}, "notes": "fragile"})
r = table.update_item(
Key=key,
UpdateExpression=("SET #st = :st, page_views = if_not_exists(page_views, :zero) + :one "
"REMOVE notes ADD tags :t"),
ExpressionAttributeNames={"#st": "status"},
ExpressionAttributeValues={":st": "PAID", ":zero": 0, ":one": 1, ":t": {"vip"}},
ReturnValues="ALL_NEW",
)
item = r["Attributes"]
print(item["status"], item["page_views"], sorted(item["tags"]), "notes" in item)
# PAID 1 ['new', 'vip'] FalseRemember
- UpdateExpression clauses: SET, REMOVE, ADD, DELETE
- Values go in
:placeholders, reserved or odd names in#placeholders if_not_existsandADDgive safe defaults and atomic counters- Conditions use functions like attribute_exists and begins_with
Watch out for
- Writing an attribute called status or name directly in an expression and getting a reserved-word ValidationException.