Intermediário6 min de leitura

DynamoDB Expressões de condição chave

Uma expressão de condição chave é o KeyConditionExpression que você passa para um Query — a única parte da solicitação que DynamoDB usa para encontrar itens. Tudo else (filtros, projeções) é executado depois que a leitura já foi medida.

O que é uma expressão de condição chave em DynamoDB?

Uma expressão de condição chave é KeyConditionExpression em um Query que informa a DynamoDB quais itens ler. Odeve ser uma igualdade (PK = :v); oleva um operador de intervalo - =, <, <=, >, >=, BETWEEN ou begins_with. Ele decide o que é lido e cobrado, diferentemente de um filtro.

  • Odeve ser uma igualdade. PK = :v e nada mais - não intervalos, sem begins_with, sem IN. DynamoDB faz hash para localizar uma partição.
  • Ousa um operador de intervalo. =, <, <=, >, >=, BETWEEN, ou begins_with — é aqui que você corta um.
  • Não é um filtro. Uma condição chave decide o que será lido e cobrado; um FilterExpression apenas corta o resultado depois que você paga pela leitura.
  • As chaves de classificação são ordenadas por bytes. Os operadores de intervalo são comparados lexicograficamente, portanto como você formata a string da chave de classificação é o seu poder de consulta.

Por que a chave de partição está bloqueada para igualdade

DynamoDB armazena itens fazendo hash da chave de partição para uma partição física. Um hash fornece um local, não um intervalo - portanto, não há nada para verificar através.

É por isso que PK > :v ou begins_with(PK, :v) são rejeitados completamente. O motor não é possível responder "todas as partições cuja chave começa com X" sem ler o todo table, que é exatamente o Scan que foi criado para evitar.

Vindo de SQL, parece ao contrário: WHERE id LIKE 'order%' é trivial em Postgres. Em DynamoDB a chave de partição é um endereço, não uma coluna pesquisável.

A chave de classificação é onde mora o poder

Dentro de uma partição, os itens são armazenados classificados pela chave de classificação. Essa ordem é o que os operadores de alcance exploram - DynamoDB busca uma posição e lê adiante.

OperadorUse-o para
SK = :vUm item exatoUm filho específico por sua chave
SK < / <= / > / >= :vUma fatia aberta"Tudo depois deste ponto"
SK ENTRE :a E :bUma gama fechada (inclusiva)Uma janela limitada — um intervalo de datas
begins_with(SK, :p)Uma fatia de prefixoUm tipo ou hierarquia sob PK

Não há LIKE, nem CONTAINS, nem ENDS_WITH na chave. Substring e a correspondência de sufixos não é ordenada por bytes, portanto, forçaria uma leitura completa - por design, o API não vai deixar você. A correspondência de substring existe via contains() em um FilterExpression (onde você já pagou pela leitura); correspondência de sufixo não está disponível no servidor - armazene uma chave invertida ou filtre-a lado do cliente. (AWS: Expressões de condição chave)

Um exemplo prático: mensagens em um aplicativo de bate-papo

Digamos que você esteja criando um bate-papo baseado em canal. Uma tabela, particionada por canal, classificados por hora da mensagem. Esquema de chave original:

  • Chave de partição ChannelRefCH#{channelId}
  • Chave de classificação PostedAt — um carimbo de data/hora ISO-8601, MSG#2026-06-23T14:05:00Z

O prefixo MSG# mantém as linhas da mensagem classificáveis e distintas de qualquer outra linha tipo que você pode colocar no mesmo canal (configuração fixada, associação).

Carregue as mensagens mais recentes de um canal. Apenas a chave de partição, as mais recentes primeiro:

KeyConditionExpression      ChannelRef = :ch
ExpressionAttributeValues   { ":ch": "CH#general" }
ScanIndexForward            false

ScanIndexForward: false percorre a coleção classificada ao contrário - a maneira mais barata para obter "o mais recente primeiro" sem classificar o lado do cliente.

Um dia específico com begins_with. Como o carimbo de data/hora é a chave de classificação e é 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ê todas as mensagens em 23/06/2026 e nada mais - DynamoDB busca o prefixo e para quando cai no 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 as 14:00 horas", um intervalo inclusivo supera 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 em ambos os limites, então escolha seus pontos finais deliberadamente - um off-by-one aqui descarta ou duplica silenciosamente uma mensagem de borda.

Você pode montar e copiar qualquer uma dessas expressões, com o Mapa ExpressionAttributeValues preenchido para você, no DynamoDB construtor de expressões — útil para acertando a sintaxe begins_with e BETWEEN na primeira vez.

Este construtor é predefinido para uma consulta pk =… AND begins_with(sk, …) — altere o operador para ver a atualização KeyConditionExpression:

Monte sua requisição
Código gerado
new QueryCommand({
  "TableName": "AuditLog",
  "KeyConditionExpression": "#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)",
  "ExpressionAttributeNames": {
    "#hashKey": "pk",
    "#rangeKey": "sk"
  },
  "ExpressionAttributeValues": {
    ":hashKeyValue": {
      "S": "TENANT#acme"
    },
    ":rangeKeyValue": {
      "S": "EVENT#2026-06"
    }
  }
})

Veja no DynoTable

Execute a mesma condição chave em uma partição de canal real. No momento em que você definir um filtro de chave de partição, DynoTable emite um Query — então você carrega apenas aquela fatia, não toda a coleção.

A armadilha: confundir uma condição chave com um filtro

O erro caro é usar FilterExpression para fazer o trabalho de uma chave. Um filter não pode nem fazer referência a PostedAt - é a chave de classificação e DynamoDB rejeita um filtro em um atributo chave com uma ValidationException. Portanto, a solução alternativa é duplique a data em um atributo simples e não-chave (MessageDate) e filtre isso em vez disso:

KeyConditionExpression   ChannelRef = :ch
FilterExpression         begins_with(MessageDate, :day)

Isso parece equivalente à condição chave begins_with acima e retorna o mesmas linhas - mas lê primeiro a partição inteira do canal e depois descarta tudo fora do dia. Você é cobrado pela leitura completa.

Os filtros nunca reduzem o custo de leitura. Eles correm depois que DynamoDB mediu os itens, a mesma arma que um Scan filtrado. Se um predicado pode ir na condição chave, ele pertence a esse lugar.

Corrija-o a montante. Se um padrão de acesso não puder ser expresso como uma igualdade PK além de um intervalo de chaves de classificação, é um sinal de modelagem. Remodele a chave de classificação ou adicione um índice codificado para o padrão - consulte GSI vs LSI e design de tabela única para saber como organizar as chaves.

Armadilhas e próximos passos

  • A chave de partição é sempre =. Nunca há intervalos. Se você precisar de uma variedade de partições, você superou um único Query.
  • Uma condição de chave de classificação por consulta. Você não pode AND dois predicados de chave de classificação; escolha BETWEEN ou begins_with, não ambos.
  • Palavras reservadas precisam de aliases. Uma chave chamada Timestamp ou Name deve usar ExpressionAttributeNames (#ts) ou os erros de consulta. (AWS: palavras reservadas)
  • BETWEEN é inclusivo. Ambos os pontos de extremidade são correspondentes — projete seus limites consequentemente.

Elabore suas principais condições no construtor de expressão, então tente DynoTable para executá-los em suas próprias tabelas e ver exatamente qual fatia cada condição chave retorna.

Atualizado