Query DynamoDB sur un GSI en Node.js (AWS SDK v3)
Une requête sur GSI est une Query ordinaire plus IndexName, et deux choses cessent alors de se comporter comme une requête sur table : le flag de cohérence dont tu as l'habitude devient une erreur, et le curseur de pagination gagne un attribut supplémentaire. Ici, AlbumTitle-index récupère les morceaux par album, ce que la table de base (Artist + SongTitle) ne peut pas faire sans un scan.
Code
import {DynamoDBClient, QueryCommand} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({region: 'us-east-1'});
const items = [];
let lastEvaluatedKey;
do {
const response = await client.send(
new QueryCommand({
TableName: 'Music',
IndexName: 'AlbumTitle-index',
KeyConditionExpression: '#hashKey = :hashKeyValue',
ExpressionAttributeNames: {
'#hashKey': 'AlbumTitle'
},
ExpressionAttributeValues: {
':hashKeyValue': {S: 'Danzon'}
},
ExclusiveStartKey: lastEvaluatedKey
})
);
items.push(...(response.Items ?? []));
lastEvaluatedKey = response.LastEvaluatedKey;
} while (lastEvaluatedKey);
console.log(`Found ${items.length} songs on the album`);Le curseur fait trois attributs de large, pas deux
Lance la boucle ci-dessus sur 300 morceaux d'un même album et regarde le LastEvaluatedKey qu'elle te rend :
table query -> ['Artist', 'SongTitle']
GSI query -> ['AlbumTitle', 'Artist', 'SongTitle']Une clé de GSI n'est pas unique : la clé d'index seule ne peut donc pas reprendre un parcours. DynamoDB renvoie la clé d'index et la clé de la table de base ensemble, et les deux doivent repartir intactes dans ExclusiveStartKey. C'est pour ça qu'un curseur bricolé à la main qui stocke « la dernière clé de tri vue » fonctionne sur une table et perd ou répète silencieusement des éléments sur un index — et pourquoi persister cette clé côté client est une mauvaise idée quand la clé de table est un identifiant utilisateur que tu préférerais ne pas divulguer.
ConsistentRead: true est un 400, pas une amélioration
L'intuition, c'est qu'une lecture fortement cohérente coûte plus de capacité et te donne des données plus fraîches. Sur un GSI, elle te coûte la requête :
ValidationException: Consistent reads are not supported on global secondary indexes
HTTP 400La référence de l'API est tout aussi tranchée : "Strongly consistent reads are not supported on global secondary indexes. If you query a global secondary index with ConsistentRead set to true, you will receive a ValidationException." Scan sur un GSI rejette le même flag avec le même message. Les index secondaires locaux, eux, l'acceptent.
Reproduit le 2026-07-28 sur DynamoDB Local (amazon/dynamodb-local) avec @aws-sdk/client-dynamodb 3.1095.0 sur node v24.18.0. Le texte d'erreur et la forme des clés sont la sortie du moteur lui-même.
Explication
IndexNamene remplace pasTableName. Les deux vont dans la même commande, et laKeyConditionExpressionnomme alors la clé de partition de l'index (AlbumTitle), pas celle de la table, avec le même jeu d'opérateurs qu'une requête sur table.- Tu obtiens la projection et rien d'autre. Une requête sur GSI renvoie ce que l'index projette (
ALL,KEYS_ONLYou la listeINCLUDE), et selon la référence de l'API "global secondary index queries cannot fetch attributes from the parent table". Un attribut manquant signifie unGetItemde suivi sur la clé de base, ou une projection plus large et un index recréé. - Les éléments dépourvus de la clé d'index n'apparaissent jamais. C'est le motif de l'index creux, et c'est une fonctionnalité : indexe uniquement les lignes avec
status = "OPEN"et le GSI reste petit. C'est aussi la raison pour laquelle une requête sur GSI peut renvoyer moins d'éléments que prévu sans lever la moindre erreur. - La réplication est asynchrone, donc une écriture qui vient d'atterrir sur la table peut ne pas encore être dans l'index. Prévois-le dans les chemins lecture-après-écriture plutôt que de réessayer en boucle serrée.
Le faire visuellement
Ajouter un GSI après coup est la façon coûteuse d'apprendre tout ça. Le planificateur de single-table design prend tes modèles d'accès et détermine lesquels ont besoin d'une clé d'index et lesquels la table de base sert déjà.
Pour parcourir les index d'une table et lancer des requêtes GSI depuis un formulaire, avec une grille paginée, télécharge DynoTable.
Exemples liés
- Query DynamoDB sur un GSI en Python — la même requête d'index avec boto3.
- Query DynamoDB sur un GSI avec l'AWS CLI — la même requête d'index depuis le shell.
- Query DynamoDB en Node.js — interroger la table de base.
- GSI vs LSI — quel type d'index convient au modèle d'accès.
- Pourquoi les GSI sont en cohérence à terme — le décalage de réplication expliqué.
- "The table does not have the specified index" — le nom de l'index ne correspond pas (les noms de GSI sont sensibles à la casse).
- "Consistent reads are not supported on global secondary indexes" — pourquoi le flag de lecture cohérente échoue sur un GSI.