DynamoDB: einen GSI in Node.js abfragen (AWS SDK v3)
Eine GSI-Query ist eine normale Query plus IndexName — und dann verhalten sich zwei Dinge nicht mehr wie bei einer Tabellen-Query: Das Konsistenz-Flag, das du gewohnt bist, wird zum Fehler, und der Pagination-Cursor bekommt ein zusätzliches Attribut. Hier holt AlbumTitle-index Songs nach Album, was die Basistabelle (Artist + SongTitle) ohne einen Scan nicht kann.
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`);Der Cursor ist drei Attribute breit, nicht zwei
Lass die Schleife oben gegen 300 Songs auf einem Album laufen und sieh dir den LastEvaluatedKey an, den sie zurückgibt:
table query -> ['Artist', 'SongTitle']
GSI query -> ['AlbumTitle', 'Artist', 'SongTitle']Ein GSI-Key ist nicht eindeutig, der Index-Key allein kann einen Scan also nicht fortsetzen. DynamoDB gibt den Index-Key und den Basistabellen-Key zusammen zurück, und beide müssen unangetastet in ExclusiveStartKey zurück. Deshalb funktioniert ein selbstgebauter Cursor, der „den letzten Sort Key, den ich gesehen habe" speichert, auf einer Tabelle und verliert oder wiederholt auf einem Index stillschweigend Items — und deshalb ist es eine schlechte Idee, diesen Key an einen Client zu persistieren, wenn der Tabellen-Key eine User-ID ist, die du lieber nicht preisgibst.
ConsistentRead: true ist ein 400, kein Upgrade
Der Instinkt sagt: Ein stark konsistentes Lesen kostet mehr Kapazität und du bekommst frischere Daten. Auf einem GSI kostet es dich den Request:
ValidationException: Consistent reads are not supported on global secondary indexes
HTTP 400Die API-Referenz ist genauso unmissverständlich: "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 auf einem GSI lehnt dasselbe Flag mit derselben Nachricht ab. Local Secondary Indexes akzeptieren es sehr wohl.
Am 2026-07-28 gegen DynamoDB Local (amazon/dynamodb-local) mit @aws-sdk/client-dynamodb 3.1095.0 auf node v24.18.0 reproduziert. Der Fehlertext und die Key-Formen sind die eigene Ausgabe der Engine.
Erklärung
IndexNameersetztTableNamenicht. Beide gehören in denselben Command, und dieKeyConditionExpressionbenennt dann den Partition Key des Index (AlbumTitle), nicht den der Tabelle, mit demselben Operatorsatz wie eine Tabellen-Query.- Du bekommst die Projection und sonst nichts. Eine GSI-Query gibt zurück, was der Index projiziert (
ALL,KEYS_ONLYoder dieINCLUDE-Liste), und laut API-Referenz "global secondary index queries cannot fetch attributes from the parent table". Ein fehlendes Attribut bedeutet ein nachgelagertesGetItemauf dem Basis-Key — oder eine breitere Projection und einen neu erstellten Index. - Items ohne den Index-Key tauchen nie auf. Das ist das Sparse-Index-Muster, und es ist ein Feature: Indiziere nur die Zeilen mit
status = "OPEN"und der GSI bleibt klein. Es ist auch der Grund, warum eine GSI-Query weniger Items zurückgeben kann, als du erwartest, ohne einen Fehler zu melden. - Die Replikation ist asynchron, ein Write, der gerade auf der Tabelle gelandet ist, kann also noch nicht im Index sein. Plane das in Read-after-Write-Pfaden ein, statt in einer engen Schleife zu wiederholen.
Mach es visuell
Einen GSI nachträglich hinzuzufügen ist der teure Weg, das zu lernen. Der Single-Table-Design-Planer nimmt deine Zugriffsmuster und ermittelt, welche davon einen Index-Key brauchen und welche die Basistabelle schon bedient.
Um die Indizes einer Tabelle zu durchsuchen und GSI-Queries aus einem Formular auszuführen, mit paginiertem Grid, lade DynoTable herunter.
Verwandte Beispiele
- DynamoDB: einen GSI in Python abfragen — dieselbe Index-Query mit boto3.
- DynamoDB: einen GSI mit der AWS CLI abfragen — dieselbe Index-Query aus der Shell.
- DynamoDB Query in Node.js — die Basistabelle abfragen.
- GSI vs. LSI — welcher Indextyp zum Zugriffsmuster passt.
- Warum GSIs letztendlich konsistent sind — die Replikationsverzögerung erklärt.
- „The table does not have the specified index" — der Indexname passt nicht (GSI-Namen unterscheiden Groß-/Kleinschreibung).
- „Consistent reads are not supported on global secondary indexes" — warum das Consistent-Read-Flag auf einem GSI scheitert.