Intermediário5 min de leitura

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 = :v e nada mais — sem intervalos, sem begins_with, sem IN. O DynamoDB faz o hash dela para localizar uma partição.
  • A chave de ordenação aceita um operador de intervalo. =, <, <=, >, >=, BETWEEN, ou begins_with — é aqui que você fatia uma coleção de itens.
  • Não é um filtro. Uma key condition decide o que é lido e cobrado; uma FilterExpression só 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.

OperadorUse para
SK = :vUm item exatoUm filho específico pela sua chave
SK < / <= / > / >= :vUma fatia em aberto"Tudo depois deste ponto"
SK BETWEEN :a AND :bUm intervalo fechado (inclusivo)Uma janela limitada — um intervalo de datas
begins_with(SK, :p)Uma fatia de prefixoUm 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 ChannelRefCH#{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:  false

ScanIndexForward: 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 único Query.
  • Uma condição de chave de ordenação por consulta. Você não pode fazer AND de dois predicados de chave de ordenação; escolha BETWEEN ou begins_with, não os dois.
  • Palavras reservadas precisam de aliases. Uma chave chamada Timestamp ou Name deve usar ExpressionAttributeNames (#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.

Atualizado