Query do DynamoDB em Go (AWS SDK v2)

Query lê uma partição, opcionalmente estreitada pela chave de ordenação (Query vs Scan explica quando essa é a escolha certa, e expressões de condição de chave lista todos os operadores permitidos). O que o AWS SDK for Go v2 acrescenta é o QueryPaginator, que transforma o loop de LastEvaluatedKey em um loop for e, ao fazer isso, silenciosamente tira sua chance de parar.

Código

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

Explicação

O Limit não limita o que o paginador lê. Esse é o que custa dinheiro. Definir Limit: aws.Int32(5) na entrada acima e rodar sobre uma partição de 30 itens de ~60 KB cada produziu:

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

Todos os trinta itens voltaram. Limit é um tamanho de página, e a função do paginador é continuar pedindo até as páginas acabarem, então os dois se anulam exatamente. A AWS o define como "the maximum number of items to evaluate (not necessarily the number of matching items)" (consultado em 2026-07-28). Se você quer os cinco primeiros itens, dê break no loop você mesmo depois da primeira página.

Páginas pequenas custam um pouco mais, não menos. A mesma partição lida sem Limit pagina em duas páginas por 220,0 unidades; com Limit: 5 foram sete chamadas por 222,0. Cada página arredonda o próprio total de bytes para o próximo múltiplo de 4 KB, então mais páginas significa mais arredondamento, além de seis idas e voltas extras de latência. Baixar o Limit para "ler menos" não te dá nem uma coisa nem outra.

O loop sempre faz uma chamada a mais do que existe de dados. A página 7 acima devolveu zero itens. O DynamoDB devolve um LastEvaluatedKey sempre que o Limit foi atingido, havendo ou não algo em seguida, e o HasMorePages() acredita nele. Então um paginador com Limit termina em uma requisição desperdiçada, e qualquer efeito colateral por página (uma barra de progresso, um flush de lote, uma linha de log) dispara uma vez contra uma página vazia. Proteja-se com len(page.Items).

HasMorePages() é true antes da primeira requisição. Ele é inicializado como true para que o loop for sequer entre, o que significa que é uma condição de loop, não uma verificação de "tem dados". Chamá-lo para decidir se vale a pena consultar sempre diz sim.

Os erros aparecem por página, e uma leitura parcial é um estado real. NextPage retorna o mesmo erro embrulhado do smithy que qualquer outra chamada, então desembrulhe com errors.As contra *types.ProvisionedThroughputExceededException e afins em vez de comparar strings. O log.Fatalf do trecho joga fora as páginas já coletadas; em um serviço você geralmente quer manter items e reportar até onde conseguiu chegar.

ScanIndexForward é a única forma de ler uma partição de trás para frente. Defina ScanIndexForward: aws.Bool(false) para ordem decrescente de chave de ordenação. Não existe "sort by" para mais nada: a ordem vem da chave de ordenação, e se você precisa de outra ordem, precisa de outro índice. IndexName: aws.String("...") move a consulta inteira para aquele índice.

Dois pacotes deixam isso mais curto. github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression monta a condição de chave e os dois mapas de placeholders a partir de expression.Key("Artist").Equal(expression.Value("Arturo Sandoval")), o que elimina os pares #hashKey/:hashKeyValue escritos à mão e, junto com eles, o risco de palavra reservada. attributevalue.UnmarshalListOfMaps(page.Items, &songs) transforma uma página direto em []Song.

Faça isso visualmente

Os dois mapas de placeholders são a parte que vale gerar em vez de digitar. O DynamoDB Expression Builder gratuito monta a condição de chave com os ExpressionAttributeNames e ExpressionAttributeValues correspondentes e emite o literal Go, para que os nomes e valores não possam se descolar.

Para rodar consultas nas suas próprias tabelas — formulário de condição de chave, uma grade que pagina conforme você rola, copiar a requisição de volta como Go — baixe o DynoTable.

Exemplos relacionados

Referências

Medido em 2026-07-28 no go1.26.5 com aws-sdk-go-v2/service/dynamodb v1.62.1, contra o DynamoDB Local (amazon/dynamodb-local) na porta 9000, sobre uma partição de 30 itens de ~60 KB cada. As contagens por página e as leituras de capacidade são saída capturada. O DynamoDB Local aplica as regras de arredondamento documentadas; trate as unidades absolutas como uma demonstração do formato e meça o serviço antes de dimensionar.

Monte esta solicitação visualmente

Componha esta operação no Construtor de Consultas do DynamoDB gratuito — key condition, filtro, índice, Limit, ordem de classificação e um laço de paginação — e copie de volta como um programa executável para SDK v3, CLI ou boto3.

Abrir o Construtor de Consultas do DynamoDB

Trabalhe com o DynamoDB sem o Console

Um cliente desktop rápido para DynamoDB que roda o SQL de verdade que o DynamoDB não consegue — JOINs, GROUP BY, agregações — com edição visual e um agente de IA com suas próprias chaves do Bedrock.

Teste grátis de 30 dias, sem cartão de crédito — depois o plano Grátis sem limite de tempo.