DynamoDB Query en Go (AWS SDK v2)

Query lee una partición, opcionalmente acotada por la clave de ordenación (Query vs Scan cubre cuándo es la decisión correcta, y expresiones de condición de clave lista todos los operadores válidos). Lo que añade AWS SDK for Go v2 es QueryPaginator, que convierte el bucle de LastEvaluatedKey en un bucle for y, al hacerlo, te quita discretamente la oportunidad 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))
}

Explicación

Limit no acota lo que lee el paginador. Este es el que cuesta dinero. Poner Limit: aws.Int32(5) en la entrada de arriba y ejecutarlo sobre una partición de 30 Items de ~60 KB cada uno produjo:

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

Volvieron los treinta Items. Limit es un tamaño de página, y el trabajo del paginador es seguir pidiendo hasta que se acaben las páginas, así que los dos se cancelan exactamente. AWS lo define como "the maximum number of items to evaluate (not necessarily the number of matching items)" (consultado el 2026-07-28). Si quieres los cinco primeros Items, sal del bucle con break tú mismo tras la primera página.

Las páginas pequeñas cuestan un poco más, no menos. La misma partición leída sin Limit pagina en dos páginas por 220,0 unidades; con Limit: 5 hicieron falta siete llamadas por 222,0. Cada página redondea su propio total de bytes al siguiente múltiplo de 4 KB, así que más páginas significan más redondeo, más seis viajes de ida y vuelta extra de latencia. Bajar Limit para «leer menos» no te da ninguna de las dos cosas.

El bucle siempre hace una llamada más de las que hay datos. La página 7 de arriba devolvió cero Items. DynamoDB devuelve un LastEvaluatedKey siempre que se alcanzó el Limit, venga algo detrás o no, y HasMorePages() se lo cree. Así que un paginador con Limit termina en una petición desperdiciada, y cualquier efecto secundario por página (una barra de progreso, un vaciado de lote, una línea de log) se dispara una vez contra una página vacía. Protégete con len(page.Items).

HasMorePages() es true antes de la primera petición. Se inicializa a true para que el bucle for llegue a entrar, lo que significa que es una condición de bucle, no una comprobación de «hay datos». Llamarla para decidir si merece la pena consultar siempre dice que sí.

Los errores afloran por página, y una lectura parcial es un estado real. NextPage devuelve el mismo error de smithy envuelto que cualquier otra llamada, así que desenvuélvelo con errors.As contra *types.ProvisionedThroughputExceededException y compañía en lugar de comparar cadenas. El log.Fatalf del fragmento tira las páginas ya recogidas; en un servicio normalmente querrás conservar items e informar de hasta dónde llegaste.

ScanIndexForward es la única forma de leer una partición hacia atrás. Pon ScanIndexForward: aws.Bool(false) para orden descendente de clave de ordenación. No hay un «ordenar por» para nada más: el orden viene de la clave de ordenación, y si necesitas otro orden necesitas otro índice. IndexName: aws.String("...") mueve la consulta entera a ese índice.

Dos paquetes acortan esto. github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression construye la condición de clave y los dos mapas de marcadores a partir de expression.Key("Artist").Equal(expression.Value("Arturo Sandoval")), lo que elimina los pares #hashKey/:hashKeyValue escritos a mano y con ellos el riesgo de palabra reservada. attributevalue.UnmarshalListOfMaps(page.Items, &songs) convierte una página directamente en []Song.

Hazlo visualmente

Los dos mapas de marcadores son la parte que vale la pena generar en lugar de teclear. El Generador de expresiones de DynamoDB gratuito monta la condición de clave con sus ExpressionAttributeNames y ExpressionAttributeValues correspondientes y emite el literal de Go, así que los nombres y los valores no pueden separarse.

Para ejecutar consultas contra tus propias tablas — formulario de condición de clave, una cuadrícula que pagina mientras te desplazas, copiar la petición de vuelta como Go — descarga DynoTable.

Ejemplos relacionados

Referencias

Medido el 2026-07-28 en go1.26.5 con aws-sdk-go-v2/service/dynamodb v1.62.1, contra DynamoDB Local (amazon/dynamodb-local) en el puerto 9000, sobre una partición de 30 Items de ~60 KB cada uno. Los recuentos por página y las lecturas de capacidad son salida capturada. DynamoDB Local aplica las reglas de redondeo documentadas; toma las unidades absolutas como una demostración de la forma y mide el servicio antes de dimensionar.

Construye esta solicitud visualmente

Compón esta operación en el Generador de consultas de DynamoDB gratuito —condición de clave, filtro, índice, Limit, orden de clasificación y un bucle de paginación— y cópiala de vuelta como un programa ejecutable para SDK v3, CLI o boto3.

Abrir el Generador de consultas de DynamoDB

Trabaja con DynamoDB sin la Consola

Un cliente de escritorio rápido para DynamoDB que ejecuta el SQL real que DynamoDB no puede — JOINs, GROUP BY, agregaciones — con edición visual y un agente de IA con tus propias claves de Bedrock.

Prueba gratuita de 30 días, sin tarjeta — después, el plan Free sin límite de tiempo.