PutItem de DynamoDB en Node.js (SDK de AWS v3)

PutItem escribe un Item entero y reemplaza cualquier Item existente con la misma clave principal (las acciones basadas en Item cubren en qué se diferencia de UpdateItem). El cliente v3 envía DynamoDB JSON directamente, así que Item contiene valores { S: … } / { N: … } en lugar de JavaScript plano.

Código

import {DynamoDBClient, PutItemCommand} from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({region: 'us-east-1'});

const command = new PutItemCommand({
  TableName: 'Music',
  Item: {
    Artist: {S: 'Arturo Sandoval'},
    SongTitle: {S: 'Cubano Chant'},
    AlbumTitle: {S: 'Danzon'},
    Year: {N: '1994'},
    Awards: {N: '0'}
  },
  ConditionExpression: 'attribute_not_exists(#cond0) AND attribute_not_exists(#cond1)',
  ExpressionAttributeNames: {
    '#cond0': 'Artist',
    '#cond1': 'SongTitle'
  }
});

try {
  await client.send(command);
  console.log('Song written');
} catch (err) {
  if (err.name === 'ConditionalCheckFailedException') {
    console.log('A song with that key already exists — not overwritten');
  } else {
    throw err;
  }
}

Explicación

err.name es la comprobación correcta, y no es lo único que trae el error. Capturar la condición fallida de arriba e imprimir el objeto dio:

err.name                     ConditionalCheckFailedException
err instanceof Error         true
err.message                  The conditional request failed
err.$metadata.httpStatusCode 400

Cada error de v3 lleva $metadata con el código de estado, el id de la petición y el número de intento, que es lo que quieres en una línea de log. err.name es estable entre los paquetes modulares; instanceof ConditionalCheckFailedException también funciona, pero arrastra la clase como import de valor, así que los bundlers la conservan.

El error puede entregarte el Item que bloqueó la escritura. Añade ReturnValuesOnConditionCheckFailure: 'ALL_OLD' al comando y err.Item llega relleno: cinco atributos en la ejecución de arriba, con Year como {"N":"1994"}. La mayoría de los manejadores de solo creación hacen un GetItem tras el fallo para averiguar qué había ya. Ese viaje de ida y vuelta es evitable. (ReturnValues: 'ALL_OLD' es el primo del camino de éxito; ReturnValues cubre el resto.)

marshall() rechaza más entradas de las que esperas. Cambiar el Item tipado de esta página por DynamoDBDocumentClient y objetos planos es el siguiente paso habitual, y @aws-sdk/util-dynamodb es estricto por defecto. Tres excepciones reales, literales:

{Genre: undefined}   Pass options.removeUndefinedValues=true to remove undefined values from map/array/set.
{tags: new Set()}    Pass a non-empty set, or options.convertEmptyValues=true.
{n: 9007199254740993} Number 9007199254740992 is greater than Number.MAX_SAFE_INTEGER. Use NumberValue from @aws-sdk/lib-dynamodb.

La primera es la que llega a producción: un campo opcional que es undefined en vez de estar ausente lanza en tiempo de marshalling, y removeUndefinedValues: true en DynamoDBDocumentClient.from(client, {marshallOptions}) es el arreglo estándar.

Lee otra vez la tercera línea. El literal era 9007199254740993; el mensaje cita 9007199254740992. JavaScript ya había redondeado el valor antes de que el SDK lo viera siquiera, así que el SDK informa de lo que recibió. Esta es toda la razón por la que DynamoDB transporta N como cadena: soporta 38 dígitos de precisión, y un number de JS soporta de 15 a 17. Todo lo que sea realmente un identificador va en S, y todo lo que sea realmente un decimal va en NumberValue o en una cadena que formatees tú.

ConditionExpression cuesta capacidad de escritura incluso cuando dice que no. AWS: "if the expression evaluates to false, DynamoDB still consumes write capacity units from the table" (consultado el 2026-07-28). Un bucle cerrado de reintento de solo creación se factura por intento. Como calibración, un put con éxito de un Item de ~15 KB informó de "CapacityUnits": 15; las escrituras redondean al alza por cada 1 KB, en vez de los 4 KB que usan las lecturas.

Los alias son estructurales. #cond0/#cond1 resuelven a Artist/SongTitle a través de ExpressionAttributeNames. Los nombres en línea funcionan hasta que uno choca con una palabra reservada, y entonces la expresión falla por un atributo que ni tocaste.

Hazlo visualmente

Las reglas de marshalling de arriba son más fáciles de comprobar viendo ambas formas una al lado de la otra. El conversor de DynamoDB JSON gratuito convierte JSON plano a la forma tipada { S: … } y viceversa, para que confirmes qué habría producido marshall() antes de enviarlo.

Para escribir y editar Items contra tus propias tablas — un formulario por atributo, selectores de tipo, copiar el resultado de vuelta como código del SDK v3 —, descarga DynoTable.

Guías relacionadas

Referencias

Reproducido el 2026-07-28 en Node v24.18.0 con @aws-sdk/client-dynamodb 3.1095.0 y @aws-sdk/util-dynamodb 3.996.7, contra DynamoDB Local (amazon/dynamodb-local) en el puerto 9000. Las cadenas de error, la forma del objeto y la lectura de capacidad son salida capturada, copiada literalmente.

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.