Consultar un GSI de DynamoDB en Python (boto3)
Una consulta a un GSI es un query normal más IndexName, y AlbumTitle-index nos da las canciones por álbum, un patrón de acceso que la clave de tabla Artist + SongTitle no puede servir. Lo que cambia en Python es el manejo de errores: los dos errores de índice más comunes fallan en capas distintas de boto3, y solo uno de ellos se puede capturar por clase de excepción.
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 ni siquiera compila, mucho menos captura
Añade ConsistentRead=True a la consulta de arriba y boto3 lanza esto, tanto en la API de cliente como en la de recurso:
botocore.exceptions.ClientError: An error occurred (ValidationException) when
calling the Query operation: Consistent reads are not supported on global
secondary indexesEl manejador obvio es except client.exceptions.ValidationException. No existe:
AttributeError: <botocore.errorfactory.DynamoDBExceptions object> has no
attribute ValidationException. Valid exceptions are: BackupInUseException,
... IndexNotFoundException, ... ProvisionedThroughputExceededException, ...botocore genera clases de excepción a partir del modelo de servicio, y DynamoDB modela 33. ValidationException es un error a nivel de protocolo y no es una de ellas, así que la única bifurcación fiable es sobre el código:
except ClientError as exc:
if exc.response["Error"]["Code"] == "ValidationException":
...La asimetría es real. Escribe mal el nombre del índice y obtienes IndexNotFoundException, que sí está modelada y se puede capturar por clase. Usa mal la opción de consistencia y obtienes una comparación de cadenas. Ambos son errores de índice; solo uno tiene tipo.
El cursor también lleva la clave de la tabla
El paginador esconde el LastEvaluatedKey, pero merece la pena saber qué contiene en un índice. Sobre 300 canciones de un mismo álbum:
page 1: Count 271 capacity 128.5 LastEvaluatedKey ['AlbumTitle', 'Artist', 'SongTitle']
page 2: Count 29 capacity 14.0 LastEvaluatedKey []Una clave de GSI no es única, así que la clave del índice por sí sola no puede reanudar la lectura; DynamoDB devuelve juntas la clave del índice y la clave de la tabla base. Una paginación hecha a mano que solo guarde la clave del índice repite o pierde Items.
Reproducido el 2026-07-28 contra DynamoDB Local (amazon/dynamodb-local) con boto3 1.43.58 en CPython 3.14.6. El texto del error y las listas de claves son salida propia de la biblioteca.
Explicación
IndexNameno reemplaza aTableName. Ambos van en la misma llamada, y laKeyConditionExpressionnombra la clave de partición del índice (AlbumTitle) con el mismo juego de operadores que una consulta a la tabla.- Obtienes la proyección y nada más. El índice devuelve lo que proyecta (
ALL,KEYS_ONLYo la listaINCLUDE); según la referencia de la API, "global secondary index queries cannot fetch attributes from the parent table". Un atributo que falta significa unget_itemde seguimiento sobre la clave base, o una proyección más amplia en un índice nuevo. - Los Items sin la clave del índice nunca aparecen — el patrón de índice disperso. Mantiene pequeño un índice sobre
status = "OPEN", y es también por lo que una consulta a un GSI puede devolver menos de lo que esperas sin lanzar nada. - La API de recurso toma el mismo
IndexName:table.query(IndexName="AlbumTitle-index", KeyConditionExpression=Key("AlbumTitle").eq("Danzon")), con valores nativos de Python de entrada yDecimalde salida. - Una escritura en un GSI aterriza después de la escritura en la tabla. La replicación es asíncrona, así que una ruta de lectura tras escritura contra el índice fallará de vez en cuando. Reintentarla en un bucle cerrado quema capacidad sin acelerar la replicación.
Hazlo visualmente
El Generador de expresiones de DynamoDB escribe la condición de clave del índice y el mapa de valores tipados como Python listo para boto3, incluidos los envoltorios {"S": ...} que el cliente exige y la API de recurso prohíbe.
Para apuntar esa misma consulta de índice a tus propias tablas desde un formulario y leer los resultados en una cuadrícula paginada, descarga DynoTable.
Ejemplos relacionados
- Consultar un GSI de DynamoDB en Node.js — la misma consulta de índice con AWS SDK v3.
- Consultar un GSI de DynamoDB con la AWS CLI — la misma consulta de índice desde el shell.
- DynamoDB Query en Python — consultar la tabla base.
- GSI vs. LSI — qué tipo de índice encaja con el patrón de acceso.
- Por qué los GSI son eventualmente consistentes — el retardo de replicación explicado.
- "The table does not have the specified index" — el nombre del índice no coincide (los nombres de GSI distinguen mayúsculas y minúsculas).
- "Consistent reads are not supported on global secondary indexes" — por qué la opción de lectura consistente falla en un GSI.