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 indexes

El 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 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

  • IndexName no reemplaza a TableName. Ambos van en la misma llamada, y la KeyConditionExpression nombra 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_ONLY o la lista INCLUDE); según la referencia de la API, "global secondary index queries cannot fetch attributes from the parent table". Un atributo que falta significa un get_item de 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 y Decimal de 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

Referencias

Construye esta solicitud visualmente

Compón esta operación en el Generador de consultas de DynamoDB gratuito —condición de clave, filtro, índice, Limit, orden de clasificación y un bucle de paginación— y cópiala de vuelta como un programa ejecutable para SDK v3, CLI o boto3.

Abrir el Generador de consultas de DynamoDB

Trabaja con DynamoDB sin la Consola

Un cliente de escritorio rápido para DynamoDB que ejecuta el SQL real que DynamoDB no puede — JOINs, GROUP BY, agregaciones — con edición visual y un agente de IA con tus propias claves de Bedrock.

Prueba gratuita de 30 días, sin tarjeta — después, el plan Free sin límite de tiempo.