Query em um GSI do DynamoDB em Node.js (AWS SDK v3)
Uma consulta a um GSI é um Query normal mais IndexName, e então duas coisas param de se comportar como uma consulta a tabela: a flag de consistência à qual você está acostumado vira um erro, e o cursor de paginação ganha um atributo extra. Aqui o AlbumTitle-index busca músicas por álbum, algo que a tabela base (Artist + SongTitle) não consegue fazer sem um scan.
Código
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`);O cursor tem três atributos de largura, não dois
Execute o loop acima contra 300 músicas de um mesmo álbum e inspecione o LastEvaluatedKey que ele devolve:
table query -> ['Artist', 'SongTitle']
GSI query -> ['AlbumTitle', 'Artist', 'SongTitle']Uma chave de GSI não é única, então a chave do índice sozinha não consegue retomar uma varredura. O DynamoDB retorna a chave do índice e a chave da tabela base juntas, e ambas precisam voltar em ExclusiveStartKey intactas. É por isso que um cursor feito à mão que guarda "a última chave de ordenação que eu vi" funciona em uma tabela e silenciosamente perde ou repete itens em um índice — e por que persistir essa chave em um cliente é má ideia quando a chave da tabela é um id de usuário que você prefere não vazar.
ConsistentRead: true é um 400, não um upgrade
O instinto diz que uma leitura com consistência forte custa mais capacidade e te dá dados mais frescos. Em um GSI ela te custa a requisição:
ValidationException: Consistent reads are not supported on global secondary indexes
HTTP 400A referência da API é igualmente direta: "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." O Scan em um GSI rejeita a mesma flag com a mesma mensagem. Índices secundários locais aceitam, sim.
Reproduzido em 2026-07-28 contra o DynamoDB Local (amazon/dynamodb-local) com @aws-sdk/client-dynamodb 3.1095.0 no node v24.18.0. O texto do erro e os formatos de chave são a saída literal do motor.
Explicação
IndexNamenão substituiTableName. Os dois vão no mesmo comando, e aKeyConditionExpressionentão nomeia a chave de partição do índice (AlbumTitle), não a da tabela, com o mesmo conjunto de operadores de uma consulta a tabela.- Você recebe a projeção e nada além dela. Uma consulta a GSI retorna o que o índice projeta (
ALL,KEYS_ONLYou a listaINCLUDE), e conforme a referência da API "global secondary index queries cannot fetch attributes from the parent table". Um atributo faltando significa umGetItemde acompanhamento na chave base, ou uma projeção mais ampla e um índice recriado. - Itens sem a chave do índice nunca aparecem. Esse é o padrão de índice esparso, e é um recurso: indexe apenas as linhas com
status = "OPEN"e o GSI fica pequeno. Também é a razão pela qual uma consulta a GSI pode retornar menos itens do que você espera sem levantar nenhum erro. - A replicação é assíncrona, então uma escrita que acabou de cair na tabela pode ainda não estar no índice. Considere isso nos caminhos de leitura-após-escrita em vez de tentar de novo em um loop apertado.
Faça isso visualmente
Adicionar um GSI depois do fato é a forma cara de aprender isso. O planejador de single-table design recebe seus padrões de acesso e determina quais deles precisam de uma chave de índice e quais a tabela base já atende.
Para navegar pelos índices de uma tabela e executar consultas a GSI a partir de um formulário, com uma grade paginada, baixe o DynoTable.
Exemplos relacionados
- Query em um GSI do DynamoDB em Python — a mesma consulta a índice com boto3.
- Query em um GSI do DynamoDB com a AWS CLI — a mesma consulta a índice pelo shell.
- Query do DynamoDB em Node.js — consultando a tabela base.
- GSI vs. LSI — qual tipo de índice serve ao padrão de acesso.
- Por que GSIs têm consistência eventual — o atraso de replicação explicado.
- "The table does not have the specified index" — o nome do índice não corresponde (nomes de GSI diferenciam maiúsculas de minúsculas).
- "Consistent reads are not supported on global secondary indexes" — por que a flag de leitura consistente falha em um GSI.