DynamoDB UpdateItem en Node.js (AWS SDK v3)
El cliente de bajo nivel de v3 habla DynamoDB JSON en ambas direcciones, lo que significa que cada número que envías y cada número que recibes es una cadena. Eso no es una verruga; es la única forma de que un número de 38 dígitos de DynamoDB sobreviva a un lenguaje cuyo único tipo numérico es un double. También es donde están los bugs.
Código
import {DynamoDBClient, UpdateItemCommand} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({region: 'us-east-1'});
const command = new UpdateItemCommand({
TableName: 'Music',
Key: {
Artist: {S: 'Arturo Sandoval'},
SongTitle: {S: 'Cubano Chant'}
},
UpdateExpression: 'SET #upd0 = :updValue0, #upd1 = :updValue1 ADD #upd2 :updValue2',
ExpressionAttributeNames: {
'#upd0': 'Genre',
'#upd1': 'Year',
'#upd2': 'Awards'
},
ExpressionAttributeValues: {
':updValue0': {S: 'Latin Jazz'},
':updValue1': {N: '1994'},
':updValue2': {N: '1'}
},
ReturnValues: 'ALL_NEW'
});
const response = await client.send(command);
console.log(response.Attributes); // the item after the updateContra un Item que no tenía Genre ni Awards, response.Attributes vuelve como:
{"Artist":{"S":"Arturo Sandoval"},"Awards":{"N":"1"},"Genre":{"S":"Latin Jazz"},"Year":{"N":"1994"},"SongTitle":{"S":"Cubano Chant"}}typeof response.Attributes.Awards.N es "string", así que response.Attributes.Awards.N + 1 se evalúa como "11". Nada lanza un error, nada avisa, y el número equivocado se cuela en tu siguiente escritura. Parsea en la frontera: Number(response.Attributes.Awards.N).
Explicación
La expresión es una cadena normal, y v3 no la va a comprobar.
UpdateItemCommandvalida la forma del objeto de entrada, nunca la gramática dentro deUpdateExpression, así que una errata es un viaje de ida y vuelta y un 400. La gramática está en expresiones de actualización;ADD #upd2 :updValue2es el incremento atómico, y añadirConditionExpression: 'attribute_exists(Artist)'hace que la llamada sea solo de actualización en vez de un upsert.ReturnValues: 'UPDATED_NEW'suele ser el que quieres. La misma actualización devuelve{"Awards":{"N":"2"}}y nada más.ALL_NEWte manda de vuelta el Item entero en cada llamada, lo que en un Item gordo es ancho de banda que pagas por leer un solo contador.$metadataes el canal fuera de banda de v3:{"httpStatusCode":200,"requestId":"...","attempts":1,"totalRetryDelay":0}.attemptses la respuesta honesta a "¿esto se reintentó?", que importa cuando razonas sobre si una escritura no idempotente se ejecutó dos veces.ValidationExceptionno es una clase que puedas capturar, solo unnameque puedes comparar. Un alias que falta vuelve comoerr.name === 'ValidationException'conerr.messagepuesto aInvalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: Year.El document client es el otro intercambio.
@aws-sdk/lib-dynamodbtoma valores nativos de JS y hace unmarshal de la respuesta, a costa de esa seguridad de las cadenas.marshall({awards: 9007199254740993})de@aws-sdk/util-dynamodbse niega de plano:Number 9007199254740992 is greater than Number.MAX_SAFE_INTEGER. Use NumberValue from @aws-sdk/lib-dynamodb.Mira bien el número de ese mensaje. Acaba en
2, no en el3que se escribió en el literal: JavaScript ya lo había redondeado antes de que el SDK lo viera siquiera. El cliente de bajo nivel de este fragmento no puede tener ese problema, porque{N: '9007199254740993'}es texto hasta llegar al cable.
Qué te entrega una condición fallida
Añade ReturnValuesOnConditionCheckFailure: 'ALL_OLD' a la entrada y el error lanzado lleva el Item que te ganó:
name: ConditionalCheckFailedException | message: "The conditional request failed" | http: 400
err.Item: {"Artist":{"S":"Arturo Sandoval"},"Awards":{"N":"2"},"Year":{"N":"1994"},"SongTitle":{"S":"Cubano Chant"},"Genre":{"S":"Latin Jazz"}}err.Item es DynamoDB JSON en crudo, sea cual sea el cliente que lo lanzó, y es gratis. Sin él, la forma honesta de averiguar por qué falló una actualización con concurrencia optimista es un GetItem posterior que cuesta una lectura y puede estar desactualizado otra vez.
El conversor de DynamoDB JSON convierte esa carga en un objeto JS plano y al revés, que es la forma más rápida de montar un fixture a partir de un Item real. Para sacar ese Item de una tabla en vivo, para empezar, descarga DynoTable.
Guías relacionadas
- Expresiones de actualización de DynamoDB —
SET,ADD,REMOVE,DELETEy sus modismos. - Entender ReturnValues — qué te da cada opción de
ReturnValues. - "Attribute name is a reserved keyword" — por qué el mapa de alias de aquí no es opcional.
- Errores de sintaxis "Invalid UpdateExpression" — los fallos habituales de sintaxis de SET/ADD, descifrados.
Referencias
- UpdateItem — Amazon DynamoDB API Reference
- UpdateItemCommand — AWS SDK for JavaScript v3 Reference
- Update expressions — Amazon DynamoDB Developer Guide
Verificado por última vez el 2026-07-28 contra la documentación oficial de AWS enlazada arriba.