DynamoDB Scan en Node.js (AWS SDK v3)
El do/while de abajo no es código defensivo. Una página de un Scan con filtro puede volver con un array Items vacío y aun así quedar tabla por recorrer, así que parar en la primera respuesta es la forma de que un scan informe de cero coincidencias en una tabla que sí las tiene. Query vs. Scan cubre cuándo evitar la operación por completo.
Código
import {DynamoDBClient, ScanCommand} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({region: 'us-east-1'});
const items = [];
let lastEvaluatedKey;
do {
const response = await client.send(
new ScanCommand({
TableName: 'Music',
FilterExpression: '#filter0 >= :filterValue0',
ExpressionAttributeNames: {
'#filter0': 'Year'
},
ExpressionAttributeValues: {
':filterValue0': {N: '2010'}
},
ExclusiveStartKey: lastEvaluatedKey
})
);
items.push(...(response.Items ?? []));
lastEvaluatedKey = response.LastEvaluatedKey;
} while (lastEvaluatedKey);
console.log(`Matched ${items.length} items`);Dos páginas vacías, 284,5 unidades de lectura, 8 Items
El conjunto de prueba son 600 canciones de unos 3,9 KB cada una, de las cuales exactamente 8 tienen Year >= 2010, y quedan las últimas al ordenar. Esto es lo que recibe de verdad el bucle de arriba:
| Viaje de ida y vuelta | Items.length | ScannedCount | Unidades de lectura | LastEvaluatedKey |
|---|---|---|---|---|
| 1 | 0 | 271 | 128,5 | presente |
| 2 | 0 | 271 | 128,5 | presente |
| 3 | 8 | 58 | 27,5 | ausente |
Dos páginas consecutivas no devuelven nada y cuestan 128,5 unidades de lectura cada una. El código que hace if (!response.Items.length) return informa de una tabla vacía. La referencia de la API enuncia la regla sin rodeos: "a scan result can result in no items meeting the criteria and the Count will result in zero", y por separado que "a FilterExpression is applied after the items have already been read; the process of filtering does not consume any additional read capacity units".
Lee esa segunda frase como la lee tu factura. El filtro es gratis, y todo lo que descartó no lo es: 284,5 unidades de lectura para entregar 8 Items, la misma factura que pagarías sin filtro alguno.
Medido el 2026-07-28 contra DynamoDB Local (amazon/dynamodb-local) con @aws-sdk/client-dynamodb 3.1095.0 sobre node v24.18.0. Los recuentos y la capacidad son los propios campos de respuesta del motor.
Explicación
ExclusiveStartKey: lastEvaluatedKeyesundefineden la primera pasada. El serializador de v3 descarta los miembrosundefined, así que un solo objeto literal sirve para la primera petición y para todas las siguientes. Pasar{}en su lugar falla conValidationException: The provided starting key is invalid.response.Items ?? []está haciendo trabajo real. Combínalo con la tabla de arriba: la coalescencia nula mantiene honesto el acumulador en las páginas que no encontraron nada, y elwhilemantiene vivo el bucle más allá de ellas.#filter0no es decoración.Yearestá en la lista de palabras reservadas de AWS, y usarlo sin alias devuelveValidationException: Invalid FilterExpression: Attribute name is a reserved keyword; reserved keyword: Year.Limitcuenta Items leídos, no Items devueltos. Con este filtro,Limit: 10daCount: 0yScannedCount: 10. Es un mando para amortiguar picos de capacidad, no una forma de pedir diez resultados.Segment/TotalSegmentsreparten un scan de tabla completa entre varios workers. Eso divide el tiempo de reloj, no el coste — se gastan las mismas 284,5 unidades, solo que más rápido y con más concurrencia.
Lo que eso cuesta en una tabla real
284,5 unidades de lectura para 8 Items es la forma del problema, y escala linealmente con la tabla, no con el resultado. Antes de llevar a producción un scan con filtro en un camino crítico, ponle precio a la lectura de la tabla completa con tu tamaño de Item y tu tráfico en la calculadora de precios de DynamoDB, y compáralo con un GSI que convierta ese mismo patrón de acceso en un Query.
Para explorar tablas en una GUI, con cuadrículas de resultados filtradas y paginadas, descarga DynoTable en vez de escanear a ciegas desde un script.
Guías relacionadas
- Query vs. Scan — cuándo (rara vez) se justifica un
Scan. - ¿Por qué mi Scan de DynamoDB es lento y caro? — el modelo de coste y cómo evitarlo.
- DynamoDB ProvisionedThroughputExceededException — lo que un scan de tabla completa le hace a la capacidad de una tabla aprovisionada.
- DynamoDB ThrottlingException — el otro throttling, y cómo lo maneja el backoff exponencial.