Update, condition and projection expressions

Amazon DynamoDB · Practical · 14 min

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 elements
  • ADD counter :n increments a number (creating it at 0 if missing) or adds to a set
  • DELETE tags :old removes 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'] False

Remember

  • UpdateExpression clauses: SET, REMOVE, ADD, DELETE
  • Values go in :placeholders, reserved or odd names in #placeholders
  • if_not_exists and ADD give 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.

Check yourself

  1. Two clients call update_item with 'ADD views :one' on the same item at the same moment. What is the final increase?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html