DynamoDB Query in Go (AWS SDK v2)
Query liest eine Partition, optional über den Sort Key eingegrenzt (Query vs. Scan behandelt, wann das die richtige Wahl ist, und Key Condition Expressions listet jeden zulässigen Operator). Was AWS SDK for Go v2 hinzufügt, ist QueryPaginator: Er macht aus der LastEvaluatedKey-Schleife eine for-Schleife — und nimmt dir dabei klammheimlich die Möglichkeit, anzuhalten.
Code
package main
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
func main() {
ctx := context.TODO()
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("us-east-1"))
if err != nil {
log.Fatalf("load config: %v", err)
}
client := dynamodb.NewFromConfig(cfg)
paginator := dynamodb.NewQueryPaginator(client, &dynamodb.QueryInput{
TableName: aws.String("Music"),
KeyConditionExpression: aws.String(
"#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)"),
ExpressionAttributeNames: map[string]string{
"#hashKey": "Artist",
"#rangeKey": "SongTitle",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":hashKeyValue": &types.AttributeValueMemberS{Value: "Arturo Sandoval"},
":rangeKeyValue": &types.AttributeValueMemberS{Value: "C"},
},
})
var items []map[string]types.AttributeValue
for paginator.HasMorePages() {
page, err := paginator.NextPage(ctx)
if err != nil {
log.Fatalf("query: %v", err)
}
items = append(items, page.Items...)
}
fmt.Printf("Found %d items\n", len(items))
}Erklärung
Limit begrenzt nicht, was der Paginator liest. Das ist der Punkt, der Geld kostet. Limit: aws.Int32(5) am obigen Input gesetzt und über eine Partition aus 30 Items zu je ~60 KB ausgeführt, ergab:
page 1: Count=5 CU=37.0 page 5: Count=5 CU=37.0
page 2: Count=5 CU=37.0 page 6: Count=5 CU=37.0
page 3: Count=5 CU=37.0 page 7: Count=0 CU=0.0
page 4: Count=5 CU=37.0 total: 30 items, 222.0 unitsAlle dreißig Items kamen zurück. Limit ist eine Seitengröße, und die Aufgabe des Paginators ist es, weiterzufragen, bis die Seiten ausgehen — beides hebt sich also exakt auf. AWS definiert es als "the maximum number of items to evaluate (not necessarily the number of matching items)" (abgerufen am 2026-07-28). Wenn du die ersten fünf Items willst, brich die Schleife nach der ersten Seite selbst mit break ab.
Kleine Seiten kosten etwas mehr, nicht weniger. Dieselbe Partition ohne Limit gelesen paginiert in zwei Seiten für 220,0 Einheiten; mit Limit: 5 brauchte es sieben Aufrufe für 222,0. Jede Seite rundet ihre eigene Byte-Summe auf die nächste 4-KB-Grenze auf — mehr Seiten heißt also mehr Rundung, plus sechs zusätzliche Round-Trips an Latenz. Limit zu senken, um „weniger zu lesen", bringt dir keines von beidem.
Die Schleife macht immer einen Aufruf mehr, als es Daten gibt. Seite 7 oben lieferte null Items. DynamoDB gibt einen LastEvaluatedKey zurück, sobald Limit erreicht wurde — egal ob noch etwas folgt — und HasMorePages() glaubt ihm. Ein Limit-behafteter Paginator endet also mit einer vergeudeten Anfrage, und jeder Seiteneffekt pro Seite (ein Fortschrittsbalken, ein Batch-Flush, eine Log-Zeile) feuert einmal gegen eine leere Seite. Sichere das über len(page.Items) ab.
HasMorePages() ist vor der ersten Anfrage true. Es wird auf true initialisiert, damit die for-Schleife überhaupt startet — es ist also eine Schleifenbedingung und kein „gibt es Daten"-Check. Wer es aufruft, um zu entscheiden, ob sich eine Abfrage lohnt, bekommt immer ein Ja.
Fehler tauchen pro Seite auf, und ein Teil-Read ist ein realer Zustand. NextPage liefert denselben verpackten Smithy-Fehler wie jeder andere Aufruf — packe ihn also mit errors.As gegen *types.ProvisionedThroughputExceededException und Verwandte aus, statt Strings zu vergleichen. Das log.Fatalf im Snippet wirft die bereits gesammelten Seiten weg; in einem Service willst du normalerweise items behalten und melden, wie weit du gekommen bist.
ScanIndexForward ist der einzige Weg, eine Partition rückwärts zu lesen. Setze ScanIndexForward: aws.Bool(false) für absteigende Sort-Key-Reihenfolge. Ein „Sortieren nach" für irgendetwas anderes gibt es nicht: Die Reihenfolge kommt vom Sort Key, und brauchst du eine andere Reihenfolge, brauchst du einen anderen Index. IndexName: aws.String("...") verschiebt die gesamte Abfrage auf diesen Index.
Zwei Pakete machen das kürzer. github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression baut die Key Condition und beide Platzhalter-Maps aus expression.Key("Artist").Equal(expression.Value("Arturo Sandoval")) — das räumt die handgeschriebenen #hashKey/:hashKeyValue-Paare weg und mit ihnen das Risiko reservierter Wörter. attributevalue.UnmarshalListOfMaps(page.Items, &songs) macht aus einer Seite direkt ein []Song.
Mach es visuell
Die beiden Platzhalter-Maps sind der Teil, den man besser generieren als tippen lässt. Der kostenlose DynamoDB Expression Builder setzt die Key Condition mit passenden ExpressionAttributeNames und ExpressionAttributeValues zusammen und gibt das Go-Literal aus, sodass Namen und Werte nicht auseinanderdriften können.
Um Abfragen gegen deine eigenen Tabellen auszuführen — Key-Condition-Formular, ein Grid, das beim Scrollen nachlädt, die Anfrage als Go wieder herauskopieren — lade DynoTable herunter.
Verwandte Beispiele
- DynamoDB Query in Java — dieselbe Abfrage mit AWS SDK for Java 2.x.
- DynamoDB Scan in Go — wenn du dich nicht über einen Key in eine Partition hängen kannst.
- Paginierung —
LastEvaluatedKey,ExclusiveStartKeyund warumLimitkeine Seitengröße ist. - "Query condition missed key schema element" — die Key Condition benennt das falsche Attribut oder lässt den Partition Key aus.
- "Query key condition not supported" — ein Operator, den die Key Condition nicht nutzen kann, etwa contains oder eine zweite Sort-Key-Bedingung.
Referenzen
- Query — Amazon DynamoDB API Reference
- Use Query with an AWS SDK or CLI — Amazon DynamoDB Developer Guide
- dynamodb package — AWS SDK for Go v2 (pkg.go.dev)
- expression package — AWS SDK for Go v2 (pkg.go.dev)
- Querying tables — Amazon DynamoDB Developer Guide
Am 2026-07-28 auf go1.26.5 mit aws-sdk-go-v2/service/dynamodb v1.62.1 gegen DynamoDB Local (amazon/dynamodb-local) auf Port 9000 gemessen, über eine Partition aus 30 Items zu je ~60 KB. Die Zählungen und Kapazitätswerte pro Seite sind mitgeschnittene Ausgabe. DynamoDB Local wendet die dokumentierten Rundungsregeln an; behandle die absoluten Einheiten als Demonstration der Größenordnung und miss den Dienst, bevor du dimensionierst.