Query DynamoDB en Go (AWS SDK v2)

Query lit une partition, éventuellement restreinte par la clé de tri (Query vs Scan explique quand c'est le bon choix, et les expressions de condition de clé listent chaque opérateur autorisé). Ce que l'AWS SDK for Go v2 ajoute, c'est QueryPaginator, qui transforme la boucle sur LastEvaluatedKey en boucle for — et t'enlève au passage, discrètement, toute occasion de t'arrêter.

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))
}

Explication

Limit ne borne pas ce que le paginateur lit. C'est celui qui coûte de l'argent. En posant Limit: aws.Int32(5) sur l'entrée ci-dessus et en l'exécutant sur une partition de 30 éléments d'environ 60 Ko chacun :

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 units

Les trente éléments sont revenus. Limit est une taille de page, et le travail du paginateur est de continuer à demander jusqu'à épuisement des pages : les deux s'annulent exactement. AWS le définit comme "the maximum number of items to evaluate (not necessarily the number of matching items)" (récupéré le 2026-07-28). Si tu veux les cinq premiers éléments, fais toi-même un break après la première page.

Les petites pages coûtent légèrement plus cher, pas moins. La même partition lue sans Limit pagine en deux pages pour 220,0 unités ; à Limit: 5 il a fallu sept appels pour 222,0. Chaque page arrondit son propre total d'octets à la borne des 4 Ko supérieure : plus de pages signifie donc plus d'arrondis, plus six allers-retours de latence en plus. Baisser Limit pour « lire moins » ne t'apporte ni l'un ni l'autre.

La boucle fait toujours un appel de plus qu'il n'y a de données. La page 7 ci-dessus n'a renvoyé aucun élément. DynamoDB rend un LastEvaluatedKey dès que Limit a été atteint, qu'il reste quelque chose ou non, et HasMorePages() le croit. Un paginateur avec Limit termine donc sur une requête gâchée, et tout effet de bord par page (barre de progression, vidage de lot, ligne de log) se déclenche une fois sur une page vide. Protège-toi avec len(page.Items).

HasMorePages() vaut true avant la première requête. Il est initialisé à true pour que la boucle for s'exécute au moins une fois : c'est une condition de boucle, pas un contrôle « y a-t-il des données ». L'appeler pour décider s'il vaut la peine d'interroger répond toujours oui.

Les erreurs remontent page par page, et une lecture partielle est un état réel. NextPage renvoie la même erreur smithy enveloppée que n'importe quel autre appel : déballe-la avec errors.As contre *types.ProvisionedThroughputExceededException et compagnie plutôt que de comparer des chaînes. Le log.Fatalf de l'extrait jette les pages déjà collectées ; dans un service, tu veux généralement conserver items et signaler jusqu'où tu es allé.

ScanIndexForward est le seul moyen de lire une partition à l'envers. Pose ScanIndexForward: aws.Bool(false) pour un ordre décroissant de clé de tri. Il n'y a pas de « trier par » pour autre chose : l'ordre vient de la clé de tri, et s'il t'en faut un autre, il te faut un autre index. IndexName: aws.String("...") déplace la requête entière sur cet index.

Deux packages raccourcissent tout ça. github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression construit la condition de clé et les deux maps de placeholders à partir de expression.Key("Artist").Equal(expression.Value("Arturo Sandoval")), ce qui supprime les paires #hashKey/:hashKeyValue écrites à la main et, avec elles, le risque de mot réservé. attributevalue.UnmarshalListOfMaps(page.Items, &songs) transforme directement une page en []Song.

Le faire visuellement

Les deux maps de placeholders sont la partie qu'il vaut mieux générer que taper. Le DynamoDB Expression Builder gratuit assemble la condition de clé avec les ExpressionAttributeNames et ExpressionAttributeValues correspondants et émet le littéral Go, si bien que les noms et les valeurs ne peuvent pas diverger.

Pour lancer des requêtes sur tes propres tables — formulaire de condition de clé, grille qui pagine au défilement, copie de la requête en Go — télécharge DynoTable.

Exemples liés

Références

Mesuré le 2026-07-28 sur go1.26.5 avec aws-sdk-go-v2/service/dynamodb v1.62.1, sur DynamoDB Local (amazon/dynamodb-local) sur le port 9000, sur une partition de 30 éléments d'environ 60 Ko chacun. Les comptes par page et les mesures de capacité sont la sortie capturée. DynamoDB Local applique les règles d'arrondi documentées ; considère les unités absolues comme une démonstration de la forme et mesure le service avant de dimensionner.

Construis cette requête visuellement

Compose cette opération dans le Générateur de requêtes DynamoDB gratuit — condition de clé, filtre, index, Limit, ordre de tri et boucle de pagination — et copie-la en retour comme programme exécutable SDK v3, CLI ou boto3.

Ouvrir le Générateur de requêtes DynamoDB

Travaille avec DynamoDB sans la Console

Un client de bureau rapide pour DynamoDB qui exécute le vrai SQL que DynamoDB ne peut pas — JOINs, GROUP BY, agrégations — avec édition visuelle et un agent IA sur tes propres clés Bedrock.

Essai gratuit de 30 jours, sans carte bancaire — ensuite la formule Gratuit, sans limite de durée.