DynamoDB BatchWriteItem en Node.js (AWS SDK v3)
BatchWriteItem escribe o borra hasta 25 Items en una sola petición. No es un UpdateItem en pequeño: cada PutRequest reemplaza el Item almacenado entero, y los tipos de v3 no te dejan ningún sitio donde enganchar una condición. Operaciones por lotes en DynamoDB cubre los límites y el modelo de fallo parcial; esta página trata de la llamada de v3 y de la única forma que tiene de perder datos en silencio.
Código
import {BatchWriteItemCommand, DynamoDBClient} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({region: 'us-east-1'});
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
let requestItems = {
Music: [
{
PutRequest: {
Item: {
Artist: {S: 'Arturo Sandoval'},
SongTitle: {S: 'Cubano Chant'},
AlbumTitle: {S: 'Danzon'},
Year: {N: '1994'}
}
}
},
{
PutRequest: {
Item: {
Artist: {S: 'Arturo Sandoval'},
SongTitle: {S: 'A Mis Abuelos'},
AlbumTitle: {S: 'Danzon'},
Year: {N: '1994'}
}
}
},
{
DeleteRequest: {
Key: {Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}
}
}
]
};
let attempt = 0;
do {
const response = await client.send(new BatchWriteItemCommand({RequestItems: requestItems}));
// Writes that were throttled come back in UnprocessedItems — resubmit them
// with exponential backoff until the map is empty.
requestItems = response.UnprocessedItems;
if (requestItems && Object.keys(requestItems).length > 0) {
attempt += 1;
await sleep(Math.min(100 * 2 ** attempt, 5000));
}
} while (requestItems && Object.keys(requestItems).length > 0);
console.log('Batch written');Explicación
- El miembro con los restos es
UnprocessedItems, noUnprocessedKeys. El lado de lectura usa el otro nombre, y en JavaScript una errata aquí compila, se lee comoundefinedy convierte eldo/whileen una llamada de una sola pasada que tira al suelo las escrituras limitadas. TypeScript lo caza; JavaScript plano no. - No hay ningún sitio donde poner una condición. El tipo
WriteRequestde v3 tiene exactamente dos miembros opcionales,PutRequestyDeleteRequest, y ninguno aceptaConditionExpressionniReturnValues. Esto no es que el SDK sea conservador: la referencia de la API dice que no puedes especificar condiciones en peticiones individuales de put y delete. Si una escritura necesita una guarda, no pertenece a un lote, sino a UpdateItem con una condición o a una transacción. - Dos errores que puedes capturar, ninguno reintentable, discriminados por
err.name. Veintiséis entradas lanzanValidationException/Too many items requested for the BatchWriteItem call. Tocar una clave dos veces lanzaProvided list of item keys contains duplicates, y ese mensaje cubre también un par put+delete además de dos puts, lo que resulta raro la primera vez que lo ves. - La lista de motivos para rechazar el lote entero es más larga que los tres obvios. Junto a más de 25 peticiones, un Item de más de 400 KB y un total de más de 16 MB, DynamoDB rechaza el lote por una tabla inexistente, una clave que no encaja con el esquema, una clave de partición de más de 2048 bytes o una clave de ordenación de más de 1024 bytes. Una sola entrada mala te cuesta las 25.
- Agrupar te ahorra viajes de ida y vuelta, no capacidad. Cada entrada se factura como un
PutItemoDeleteItemindividual, redondeado hacia arriba a 1 KB, y un borrado dirigido a un Item inexistente consume igualmente una unidad de escritura.
Un PutRequest solo con la clave destruye el resto del Item
Ella Fitzgerald / Misty empieza con un AlbumTitle y un Year. Envía un PutRequest que solo lleve los dos atributos de clave:
{PutRequest: {Item: {Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}}}Luego vuelve a leerlo con ConsistentRead: true. DynamoDB Local 3.3.0 devuelve:
{
"Artist": { "S": "Ella Fitzgerald" },
"SongTitle": { "S": "Misty" }
}AlbumTitle y Year han desaparecido. La llamada tuvo éxito, UnprocessedItems era {}, y nada en la respuesta menciona los dos atributos que descartó. Un put es un reemplazo del Item entero, así que un lote montado a partir de una carga parcial (el cuerpo de una petición de la API, un subconjunto de columnas de un CSV, un resultado de Query proyectado que omitió atributos) borra todos los atributos que esa carga no llevaba.
Ese es el modo de fallo que hay que prever cuando usas un lote para algo que parece una actualización. La solución es leer primero el Item actual y fusionarlo, o dejar de agrupar y usar UpdateItem, que solo toca los atributos que nombras.
La otra razón por la que un lote de 25 Items acaba siendo de 12 es el tamaño. Las escrituras se redondean hacia arriba a 1 KB cada una para la facturación y la petición está limitada a 16 MB, así que el recuento real de bytes de un Item decide tanto tu factura como cuántos caben. La calculadora de tamaño de Item te da esa cifra por Item antes de que montes el array.
Para cargar, editar y borrar Items en masa sin escribir a mano la semántica de reemplazo, descarga DynoTable.
Ejemplos relacionados
- Escritura por lotes en DynamoDB en Python — el
batch_writer()de boto3 hace el bucle de reintento por ti. - DynamoDB BatchWriteItem con la AWS CLI — la misma escritura por lotes desde la shell.
- DynamoDB TransactWriteItems en Node.js — cuando las escrituras deben tener éxito o fallar juntas.
- Operaciones por lotes en DynamoDB — límites, fallo parcial y cuándo compensa agrupar.
- "Too many items requested for the BatchWriteItem call" — más de 25 peticiones de put/delete en un lote.
- "Provided list of item keys contains duplicates" — dos peticiones que tocan la misma clave en un lote.
Referencias
- BatchWriteItem — Amazon DynamoDB API Reference
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
- DynamoDB read and write operations (capacity unit consumption) — Amazon DynamoDB Developer Guide
Verificado por última vez el 2026-07-28 contra la documentación oficial de AWS enlazada arriba.