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 400

Die 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

  • IndexName ersetzt TableName nicht. Beide gehören in denselben Command, und die KeyConditionExpression benennt 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_ONLY oder die INCLUDE-Liste), und laut API-Referenz "global secondary index queries cannot fetch attributes from the parent table". Ein fehlendes Attribut bedeutet ein nachgelagertes GetItem auf 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

Referenzen

Diesen Request visuell bauen

Stelle diese Operation im kostenlosen DynamoDB Query Builder zusammen — Key-Bedingung, Filter, Index, Limit, Sortierreihenfolge und eine Paginierungsschleife — und kopiere sie als lauffähiges SDK-v3-, CLI- oder boto3-Programm zurück.

DynamoDB Query Builder öffnen

Mit DynamoDB ohne die Console arbeiten

Ein schneller DynamoDB-Desktop-Client, der das echte SQL ausführt, das DynamoDB nicht kann — JOINs, GROUP BY, Aggregationen — mit visueller Bearbeitung und einem KI-Agenten auf deinen eigenen Bedrock-Schlüsseln.

30 Tage kostenlos testen, keine Kreditkarte — danach der Kostenlos-Tarif ohne Zeitlimit.