PutItem DynamoDB en Node.js (AWS SDK v3)

PutItem écrit un élément entier et remplace tout élément existant portant la même clé primaire (les actions au niveau de l'élément expliquent en quoi cela diffère d'UpdateItem). Le client v3 envoie directement du DynamoDB JSON, donc Item contient des valeurs { S: … } / { N: … } plutôt que du JavaScript ordinaire.

Code

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;
  }
}

Explication

err.name est le bon test, et ce n'est pas la seule chose portée par l'erreur. Attraper la condition échouée ci-dessus et afficher l'objet a donné :

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

Chaque erreur v3 porte un $metadata avec le code de statut, l'identifiant de requête et le nombre de tentatives, c'est-à-dire ce que tu veux dans une ligne de log. err.name est stable d'un package modulaire à l'autre ; instanceof ConditionalCheckFailedException fonctionne aussi, mais tire la classe comme import de valeur, que les bundlers conservent.

L'erreur peut te remettre l'élément qui a bloqué l'écriture. Ajoute ReturnValuesOnConditionCheckFailure: 'ALL_OLD' à la commande et err.Item arrive renseigné : cinq attributs dans l'exécution ci-dessus, avec Year à {"N":"1994"}. La plupart des handlers « création uniquement » font un GetItem après l'échec pour découvrir ce qui était déjà là. Cet aller-retour est évitable. (ReturnValues: 'ALL_OLD' est le cousin du chemin de succès ; ReturnValues couvre le reste.)

marshall() refuse plus d'entrées que tu ne le crois. Remplacer l'Item typé de cette page par DynamoDBDocumentClient et des objets ordinaires est l'étape suivante habituelle, et @aws-sdk/util-dynamodb est strict par défaut. Trois exceptions réelles, mot pour mot :

{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 première est celle qui atteint la production : un champ optionnel undefined plutôt qu'absent lève au moment du marshalling, et removeUndefinedValues: true dans DynamoDBDocumentClient.from(client, {marshallOptions}) est le correctif standard.

Relis la troisième ligne. Le littéral était 9007199254740993 ; le message cite 9007199254740992. JavaScript avait déjà arrondi la valeur avant que le SDK ne la voie, donc le SDK rapporte ce qu'il a reçu. C'est toute la raison pour laquelle DynamoDB transporte N sous forme de chaîne : il conserve 38 chiffres de précision, là où un number JS en tient 15 à 17. Tout ce qui est réellement un identifiant appartient à S, et tout ce qui est réellement un décimal appartient à NumberValue ou à une chaîne que tu formates toi-même.

ConditionExpression coûte de la capacité d'écriture même quand elle dit non. AWS : "if the expression evaluates to false, DynamoDB still consumes write capacity units from the table" (récupéré le 2026-07-28). Une boucle de reprise serrée en création seule est facturée à chaque tentative. Pour l'ordre de grandeur, un put réussi d'un élément d'environ 15 Ko a rapporté "CapacityUnits": 15 ; les écritures s'arrondissent au Ko, pas aux 4 Ko des lectures.

Les alias sont porteurs. #cond0/#cond1 résolvent vers Artist/SongTitle via ExpressionAttributeNames. Les noms en clair fonctionnent jusqu'au jour où l'un d'eux entre en collision avec un mot réservé, et l'expression échoue alors sur un attribut que tu n'as pas touché.

Le faire visuellement

Les règles de marshalling ci-dessus se vérifient plus facilement en voyant les deux formes côte à côte. Le convertisseur DynamoDB JSON gratuit transforme du JSON ordinaire en la forme typée { S: … } et inversement, pour que tu confirmes ce que marshall() aurait produit avant d'envoyer.

Pour écrire et modifier des éléments dans tes propres tables — un formulaire par attribut, des sélecteurs de type, la copie du résultat sous forme de code SDK v3 — télécharge DynoTable.

Guides liés

Références

Reproduit le 2026-07-28 sur Node v24.18.0 avec @aws-sdk/client-dynamodb 3.1095.0 et @aws-sdk/util-dynamodb 3.996.7, sur DynamoDB Local (amazon/dynamodb-local) sur le port 9000. Les chaînes d'erreur, la forme de l'objet et la mesure de capacité sont de la sortie capturée, copiée telle quelle.

Travaille avec DynamoDB sans la Console

Un client de bureau rapide pour DynamoDB qui exécute le vrai SQL que DynamoDB ne peut pas — JOINs, GROUP BY, agrégations — avec édition visuelle et un agent IA sur tes propres clés Bedrock.

Essai gratuit de 30 jours, sans carte bancaire — ensuite la formule Gratuit, sans limite de durée.