DynamoDB
Null Attributes
Querying
AWS
Database Management

How do you query for a non-existent null attribute in DynamoDB

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In DynamoDB, a missing attribute and an attribute whose value is NULL are not the same thing. That difference matters when you try to find items where a field is absent or explicitly null. The second important point is that a DynamoDB Query can only use key conditions for the table or index keys. For non-key attributes, you either filter after the query or redesign the access pattern.

Missing and NULL Mean Different Things

An item can have no deletedAt attribute at all, or it can contain a deletedAt attribute whose value is the DynamoDB NULL type. Those cases need different checks.

For missing attributes, the expression concept is attribute_not_exists.

For explicit NULL attributes, the expression concept is attribute_type(..., NULL).

That distinction is easy to miss, especially if your application language treats both situations as a generic null-like value.

Use Query Only with a Key Condition

A Query must start with a partition key condition, and optionally a sort key condition. You cannot issue a table-wide query based only on “attribute does not exist.”

If you already know the partition key, you can query that partition and then apply a filter expression.

python
1import boto3
2from boto3.dynamodb.conditions import Attr, Key
3
4resource = boto3.resource("dynamodb", region_name="us-east-1")
5table = resource.Table("Orders")
6
7response = table.query(
8    KeyConditionExpression=Key("customerId").eq("C123"),
9    FilterExpression=Attr("shippedAt").not_exists()
10)
11
12print(response["Items"])

This returns matching items in that partition where shippedAt is missing.

Query for Explicit NULL

If the attribute exists and is stored as DynamoDB NULL, use an attribute-type filter.

python
1import boto3
2from boto3.dynamodb.conditions import Attr, Key
3
4resource = boto3.resource("dynamodb", region_name="us-east-1")
5table = resource.Table("Orders")
6
7response = table.query(
8    KeyConditionExpression=Key("customerId").eq("C123"),
9    FilterExpression=Attr("shippedAt").attribute_type("NULL")
10)
11
12print(response["Items"])

This is not the same as not_exists(). It only matches items where the attribute is present and typed as NULL.

When You Actually Need a Scan

If you need to search the entire table for items with a missing non-key attribute and you do not have a key-based access pattern, a Scan is the direct option.

python
1import boto3
2from boto3.dynamodb.conditions import Attr
3
4resource = boto3.resource("dynamodb", region_name="us-east-1")
5table = resource.Table("Orders")
6
7response = table.scan(
8    FilterExpression=Attr("shippedAt").not_exists()
9)
10
11print(response["Count"])

This works, but it reads far more data than a well-designed query. For large tables, it is usually a sign that the table design does not match the required lookup pattern.

Model the Access Pattern If It Matters

If “find all unshipped orders” is a common operation, encode that requirement into your schema. For example, store an explicit status attribute and index it, rather than depending on absence checks across the whole table.

DynamoDB rewards explicit access patterns. It is usually better to design for “query by status” than to rely on broad scans and filters.

Common Pitfalls

  • Treating a missing attribute and a NULL attribute as the same case.
  • Expecting a DynamoDB Query to search by a non-key condition without a key expression.
  • Forgetting that filter expressions are applied after matching items are read.
  • Using a full table scan for a frequently used access pattern.
  • Storing state implicitly through missing fields when a real status attribute would be clearer.

Summary

  • In DynamoDB, missing attributes and NULL attributes are different.
  • Use attribute_not_exists for missing attributes.
  • Use attribute_type(..., NULL) for explicit NULL values.
  • A Query still requires a key condition; filters do not replace that.
  • If the lookup is common, redesign the table or index for that access pattern.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.