Key Condition Expressions no DynamoDB
Uma key condition expression é a KeyConditionExpression que você passa a um
Query — a única parte da requisição que o DynamoDB usa para encontrar itens. Todo o
resto (filtros, projeções) roda depois que a leitura já foi medida.
O que é uma key condition expression no DynamoDB?
Uma key condition expression é a KeyConditionExpression de um Query que indica ao DynamoDB quais itens ler. A deve ser uma igualdade (PK = :v); a aceita um operador de intervalo — =, <, <=, >, >=, BETWEEN ou begins_with. Ela define o que é lido e cobrado, ao contrário de um filtro.
- A chave de partição deve ser uma igualdade.
PK = :ve nada mais — sem intervalos, sembegins_with, semIN. O DynamoDB faz o hash dela para localizar uma partição. - A chave de ordenação aceita um operador de intervalo.
=,<,<=,>,>=,BETWEEN, oubegins_with— é aqui que você fatia uma coleção de itens. - Não é um filtro. Uma key condition decide o que é lido e cobrado; uma
FilterExpressionsó apara o resultado depois que você pagou pela leitura. - Chaves de ordenação são ordenadas por bytes. Operadores de intervalo comparam lexicograficamente, então como você formata a string da chave de ordenação é o seu poder de consulta.
Por que a chave de partição é travada na igualdade
O DynamoDB armazena itens fazendo o hash da chave de partição para uma partição física. Um hash te dá uma localização, não um intervalo — então não há nada para escanear entre.
É por isso que PK > :v ou begins_with(PK, :v) são rejeitados de cara. O motor não
consegue responder "todas as partições cuja chave começa com X" sem ler a tabela inteira,
o que é exatamente o Scan que ele foi feito para evitar.
Vindo do SQL, isso parece ao contrário: WHERE id LIKE 'order%' é trivial no Postgres.
No DynamoDB a chave de partição é um endereço, não uma coluna pesquisável.
A chave de ordenação é onde o poder vive
Dentro de uma partição, itens são armazenados ordenados pela chave de ordenação. Essa ordenação é o que os operadores de intervalo exploram — o DynamoDB busca uma posição e lê para frente.
| Operador | Lê | Use para |
|---|---|---|
SK = :v | Um item exato | Um filho específico pela sua chave |
SK < / <= / > / >= :v | Uma fatia em aberto | "Tudo depois deste ponto" |
SK BETWEEN :a AND :b | Um intervalo fechado (inclusivo) | Uma janela limitada — um intervalo de datas |
begins_with(SK, :p) | Uma fatia de prefixo | Um tipo ou hierarquia sob a PK |
Não há LIKE, CONTAINS nem ENDS_WITH na chave. Correspondência de substring e sufixo
não são ordenadas por bytes, então forçariam uma leitura completa — por design, a API não
te deixa. Essas vivem na FilterExpression, onde você já pagou.
(AWS: Key condition expressions)
Um exemplo prático: mensagens em um app de chat
Digamos que você esteja construindo um chat baseado em canais. Uma tabela, particionada por canal, ordenada por horário da mensagem. Esquema de chaves original:
- Chave de partição
ChannelRef—CH#{channelId} - Chave de ordenação
PostedAt— um timestamp ISO-8601,MSG#2026-06-23T14:05:00Z
O prefixo MSG# mantém as linhas de mensagem ordenáveis e distintas de qualquer outro
tipo de linha que você possa co-localizar sob o mesmo canal (config fixada, membros).
Carregue as mensagens mais recentes de um canal. Só a chave de partição, da mais nova primeiro:
KeyConditionExpression: ChannelRef = :ch
ExpressionAttributeValues: { ":ch": "CH#general" }
ScanIndexForward: falseScanIndexForward: false percorre a coleção ordenada ao contrário — a forma barata de
obter "mais recente primeiro" sem ordenar no lado do cliente.
Um dia específico com begins_with. Como o timestamp é a chave de ordenação e está
armazenado como texto, um prefixo de data é uma fatia limpa:
KeyConditionExpression ChannelRef = :ch AND begins_with(PostedAt, :day)
:ch "CH#general"
:day "MSG#2026-06-23"
Isso lê cada mensagem em 2026-06-23 e nada mais — o DynamoDB busca o prefixo e para quando cai fora do final. Isso só funciona porque o prefixo é uma verdadeira âncora à esquerda de uma string ordenada por bytes.
Uma janela precisa com BETWEEN. Para "as mensagens durante a hora das 14:00", um
intervalo inclusivo bate um prefixo:
KeyConditionExpression ChannelRef = :ch AND PostedAt BETWEEN :lo AND :hi
:ch "CH#general"
:lo "MSG#2026-06-23T14:00:00Z"
:hi "MSG#2026-06-23T14:59:59Z"
BETWEEN é inclusivo nos dois limites, então escolha seus extremos deliberadamente — um
off-by-one aqui silenciosamente remove ou duplica uma mensagem de borda.
Você pode montar e copiar qualquer uma dessas expressões, com o mapa
ExpressionAttributeValues preenchido para você, no
DynamoDB expression builder — útil para acertar a
sintaxe de begins_with e BETWEEN de primeira.
Veja no DynoTable
Rode a mesma key condition contra uma partição de canal real e veja a capacidade consumida atualizar ao vivo, para que você possa confirmar que está lendo uma fatia — não a coleção inteira.
A cilada: confundir uma key condition com um filtro
O erro caro é recorrer a FilterExpression para fazer o trabalho de uma chave.
KeyConditionExpression: ChannelRef = :ch
FilterExpression: begins_with(PostedAt, :day)Isso parece equivalente à key condition begins_with acima e retorna as mesmas linhas
— mas lê a partição inteira do canal primeiro, depois descarta tudo fora do dia. Você
é cobrado pela leitura completa.
Filtros nunca reduzem o custo de leitura. Eles rodam depois que o DynamoDB mediu os itens,
a mesma cilada de um Scan filtrado. Se um predicado pode ir na
key condition, é aí que ele pertence.
A correção é a montante: se um padrão de acesso não pode ser expresso como uma igualdade de PK mais um intervalo de chave de ordenação, isso é um sinal de modelagem. Ou remodele a chave de ordenação, ou adicione um índice chaveado para o padrão — veja GSI vs LSI e single-table design para como dispor as chaves.
Armadilhas e próximos passos
- Chave de partição é sempre
=. Sem intervalos, nunca. Se você precisa de um intervalo entre partições, você superou um únicoQuery. - Uma condição de chave de ordenação por consulta. Você não pode fazer
ANDde dois predicados de chave de ordenação; escolhaBETWEENoubegins_with, não os dois. - Palavras reservadas precisam de aliases. Uma chave chamada
TimestampouNamedeve usarExpressionAttributeNames(#ts), ou a consulta dá erro. (AWS: reserved words) BETWEENé inclusivo. Os dois extremos são correspondidos — projete seus limites de acordo.
Rascunhe suas key conditions no expression builder, depois experimente o DynoTable para rodá-las contra suas próprias tabelas e ver a capacidade que elas de fato consomem.