Query su un GSI DynamoDB in Python (boto3)

Una query su GSI è una normale query più IndexName, e AlbumTitle-index ci dà le canzoni per album, un pattern di accesso che la chiave di tabella Artist + SongTitle non può servire. Quello che cambia in Python è la gestione degli errori: i due errori più comuni sugli indici falliscono in strati diversi di boto3, e solo uno dei due si può catturare per classe di eccezione.

Codice

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 non si compila nemmeno, figuriamoci catturare

Aggiungi ConsistentRead=True alla query qui sopra e boto3 solleva questo, sia sulla client API sia sulla resource API:

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

Il gestore ovvio è except client.exceptions.ValidationException. Non esiste:

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

botocore genera le classi di eccezione dal modello del servizio, e DynamoDB ne modella 33. ValidationException è un errore a livello di protocollo e non è tra quelle, quindi l'unico ramo affidabile è sul codice:

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

L'asimmetria è reale. Sbaglia a digitare il nome dell'indice e ottieni IndexNotFoundException, che è modellata e catturabile per classe. Usa male il flag di coerenza e ottieni un confronto di stringhe. Sono entrambi errori sugli indici; solo uno ha un tipo.

Il cursore porta con sé anche la chiave della tabella

Il paginatore nasconde LastEvaluatedKey, ma vale la pena sapere cosa contiene su un indice. Su 300 canzoni di un solo album:

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

Una chiave di GSI non è univoca, quindi la sola chiave dell'indice non può riprendere la lettura; DynamoDB restituisce insieme la chiave dell'indice e quella della tabella base. Una paginazione fatta a mano che memorizza solo la chiave dell'indice ripete o perde Item.

Riprodotto il 2026-07-28 contro DynamoDB Local (amazon/dynamodb-local) con boto3 1.43.58 su CPython 3.14.6. Il testo dell'errore e gli elenchi di chiavi sono output della libreria stessa.

Spiegazione

  • IndexName non sostituisce TableName. Vanno entrambi nella stessa chiamata, e la KeyConditionExpression nomina la chiave di partizione dell'indice (AlbumTitle) con lo stesso insieme di operatori di una query su tabella.
  • Ottieni la proiezione e nient'altro. L'indice restituisce ciò che proietta (ALL, KEYS_ONLY o l'elenco INCLUDE); secondo l'API reference "global secondary index queries cannot fetch attributes from the parent table". Un attributo mancante significa una get_item di follow-up sulla chiave base, o una proiezione più ampia su un nuovo indice.
  • Gli Item privi della chiave dell'indice non compaiono mai — il pattern dell'indice sparso. Mantiene piccolo un indice su status = "OPEN", ed è anche il motivo per cui una query su GSI può restituire meno di quanto ti aspetti senza sollevare nulla.
  • La resource API prende lo stesso IndexName: table.query(IndexName="AlbumTitle-index", KeyConditionExpression=Key("AlbumTitle").eq("Danzon")), con valori Python nativi in entrata e Decimal in uscita.
  • Una scrittura sul GSI atterra dopo quella sulla tabella. La replica è asincrona, quindi un percorso di lettura-dopo-scrittura contro l'indice ogni tanto mancherà il bersaglio. Riprovarci in un loop stretto brucia capacità senza rendere la replica più veloce.

Fallo visivamente

Il Generatore di espressioni DynamoDB scrive la condizione di chiave dell'indice e la mappa dei valori tipizzati come Python pronto per boto3, inclusi i wrapper {"S": ...} che la client API pretende e la resource API vieta.

Per puntare la stessa query su indice alle tue tabelle da un form e leggere i risultati in una griglia paginata, scarica DynoTable.

Esempi correlati

Riferimenti

Costruisci questa richiesta visivamente

Componi questa operazione nel Generatore di query DynamoDB gratuito — condizione di chiave, filtro, indice, Limit, ordine di ordinamento e un loop di paginazione — e copiala come programma eseguibile per SDK v3, CLI o boto3.

Apri il Generatore di query DynamoDB

Lavora con DynamoDB senza la Console

Un client desktop veloce per DynamoDB che esegue il vero SQL che DynamoDB non può — JOINs, GROUP BY, aggregazioni — con modifica visuale e un agente AI sulle tue chiavi Bedrock.

Prova gratuita di 30 giorni, senza carta di credito — poi il piano Free senza limiti di tempo.