Query em um GSI do DynamoDB em Python (boto3)

Uma consulta a um GSI é um query normal mais o IndexName, e o AlbumTitle-index nos dá as músicas por álbum, um padrão de acesso que a chave de tabela Artist + SongTitle não consegue atender. O que muda no Python é o tratamento de erros: os dois erros de índice mais comuns falham em camadas diferentes do boto3, e apenas um deles pode ser capturado por classe de exceção.

Código

import boto3

client = boto3.client("dynamodb")

paginator = client.get_paginator("query")

items = []
for page in paginator.paginate(
    TableName="Music",
    IndexName="AlbumTitle-index",
    KeyConditionExpression="#hashKey = :hashKeyValue",
    ExpressionAttributeNames={"#hashKey": "AlbumTitle"},
    ExpressionAttributeValues={":hashKeyValue": {"S": "Danzon"}},
):
    items.extend(page["Items"])

print(f"Found {len(items)} songs on the album")

except ValidationException nem compila, quanto mais captura

Adicione ConsistentRead=True à consulta acima e o boto3 lança isto, tanto na API de cliente quanto na de recurso:

botocore.exceptions.ClientError: An error occurred (ValidationException) when
calling the Query operation: Consistent reads are not supported on global
secondary indexes

O handler óbvio é except client.exceptions.ValidationException. Ele não existe:

AttributeError: <botocore.errorfactory.DynamoDBExceptions object> has no
attribute ValidationException. Valid exceptions are: BackupInUseException,
... IndexNotFoundException, ... ProvisionedThroughputExceededException, ...

O botocore gera as classes de exceção a partir do modelo do serviço, e o DynamoDB modela 33 delas. ValidationException é um erro de nível de protocolo e não é uma delas, então a única ramificação confiável é pelo código:

except ClientError as exc:
    if exc.response["Error"]["Code"] == "ValidationException":
        ...

A assimetria é real. Digite o nome do índice errado e você recebe IndexNotFoundException, que é modelada e capturável por classe. Use a flag de consistência de forma indevida e você recebe uma comparação de string. Ambos são erros de índice; só um tem tipo.

O cursor carrega a chave da tabela também

O paginador esconde o LastEvaluatedKey, mas vale saber o que ele guarda em um índice. Sobre 300 músicas de um mesmo álbum:

page 1: Count 271  capacity 128.5  LastEvaluatedKey ['AlbumTitle', 'Artist', 'SongTitle']
page 2: Count  29  capacity  14.0  LastEvaluatedKey []

Uma chave de GSI não é única, então a chave do índice sozinha não consegue retomar a leitura; o DynamoDB devolve a chave do índice e a chave da tabela base juntas. Uma paginação feita à mão que guarde apenas a chave do índice repete ou perde itens.

Reproduzido em 2026-07-28 contra o DynamoDB Local (amazon/dynamodb-local) com boto3 1.43.58 no CPython 3.14.6. O texto do erro e as listas de chaves são a saída da própria biblioteca.

Explicação

  • IndexName não substitui o TableName. Os dois vão na mesma chamada, e a KeyConditionExpression nomeia a chave de partição do índice (AlbumTitle), com o mesmo conjunto de operadores de uma consulta à tabela.
  • Você recebe a projeção e nada além dela. O índice devolve o que ele projeta (ALL, KEYS_ONLY ou a lista do INCLUDE); conforme a referência da API, "global secondary index queries cannot fetch attributes from the parent table". Um atributo faltando significa um get_item de acompanhamento na chave base, ou uma projeção mais ampla em um novo índice.
  • Itens sem a chave do índice nunca aparecem — o padrão de índice esparso. Ele mantém pequeno um índice sobre status = "OPEN", e é também por isso que uma consulta a um GSI pode devolver menos do que você espera sem lançar nada.
  • A API de recurso recebe o mesmo IndexName: table.query(IndexName="AlbumTitle-index", KeyConditionExpression=Key("AlbumTitle").eq("Danzon")), com valores nativos do Python na entrada e Decimal na saída.
  • Uma escrita no GSI chega depois da escrita na tabela. A replicação é assíncrona, então um caminho de leitura-após-escrita contra o índice vai eventualmente não encontrar nada. Repetir isso em um loop apertado queima capacidade sem deixar a replicação mais rápida.

Faça isso visualmente

O DynamoDB Expression Builder escreve a condição de chave do índice e o mapa de valores tipados como Python pronto para o boto3, incluindo os invólucros {"S": ...} que o cliente exige e a API de recurso proíbe.

Para apontar essa mesma consulta de índice para as suas próprias tabelas a partir de um formulário e ler os resultados em uma grade paginada, baixe o DynoTable.

Exemplos relacionados

Referências

Monte esta solicitação visualmente

Componha esta operação no Construtor de Consultas do DynamoDB gratuito — key condition, filtro, índice, Limit, ordem de classificação e um laço de paginação — e copie de volta como um programa executável para SDK v3, CLI ou boto3.

Abrir o Construtor de Consultas do DynamoDB

Trabalhe com o DynamoDB sem o Console

Um cliente desktop rápido para DynamoDB que roda o SQL de verdade que o DynamoDB não consegue — JOINs, GROUP BY, agregações — com edição visual e um agente de IA com suas próprias chaves do Bedrock.

Teste grátis de 30 dias, sem cartão de crédito — depois o plano Grátis sem limite de tempo.