node.js AWS dynamodb updateItem

You can update attributes dynamically. see below code.

export const update = (item) => {
  console.log(item)
  const Item = {
    note: "dynamic",
    totalChild: "totalChild",
    totalGuests: "totalGuests"
  };
  let updateExpression='set';
  let ExpressionAttributeNames={};
  let ExpressionAttributeValues = {};
  for (const property in Item) {
    updateExpression += ` #${property} = :${property} ,`;
    ExpressionAttributeNames['#'+property] = property ;
    ExpressionAttributeValues[':'+property]=Item[property];
  }

  
  console.log(ExpressionAttributeNames);


  updateExpression= updateExpression.slice(0, -1);
  
  
   const params = {
     TableName: TABLE_NAME,
     Key: {
      booking_attempt_id: item.booking_attempt_id,
     },
     UpdateExpression: updateExpression,
     ExpressionAttributeNames: ExpressionAttributeNames,
     ExpressionAttributeValues: ExpressionAttributeValues
   };

   return dynamo.update(params).promise().then(result => {
       return result;
   })
   
}

This is exactly what AWS.DynamoDB.DocumentClient's update method does.

There is already a sample code on how to use the update method here for AWS SDK for JavaScript in Node.js.

For example:

'use strict';

const aws = require('aws-sdk');

// It is recommended that we instantiate AWS clients outside the scope of the handler 
// to take advantage of connection re-use.
const docClient = new aws.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
    const params = {
        TableName: "MYTABLE",
        Key: {
            "id": "1"
        },
        UpdateExpression: "set variable1 = :x, #MyVariable = :y",
        ExpressionAttributeNames: {
            "#MyVariable": "variable23"
        },
        ExpressionAttributeValues: {
            ":x": "hello2",
            ":y": "dog"
        }
    };

    docClient.update(params, function(err, data) {
        if (err) console.log(err);
        else console.log(data);
    });
};

I think some of the examples are a bit confusing. If I have the following table columns

ID  | Name | Age

And I want to update the Name attribute and leave the Age attribute unchanged.

const updateName = async () => {
  const aws = require('aws-sdk');
  const docClient = new aws.DynamoDB.DocumentClient();

  const newName = 'Bob';

  const params = {
    TableName: 'myTable',
    Key: {
      ID: 'myId',
    },
    UpdateExpression: 'set Name = :r',
    ExpressionAttributeValues: {
      ':r': newName,
    },
  };

  await docClient.update(params).promise();
}

updateName();

This seemed a bit more simple.


Here is a more secure and up-to-date function to achieve this:

const {
  DynamoDBClient, UpdateItemCommand,
} = require('@aws-sdk/client-dynamodb');
const { marshall, unmarshall } = require('@aws-sdk/util-dynamodb');

const client = new DynamoDBClient({});

/**
 * Update item in DynamoDB table
 * @param {string} tableName // Name of the target table
 * @param {object} key // Object containing target item key(s)
 * @param {object} item // Object containing updates for target item
 */
const update = async (tableName, key, item) => {
  const itemKeys = Object.keys(item);

  // When we do updates we need to tell DynamoDB what fields we want updated.
  // If that's not annoying enough, we also need to be careful as some field names
  // are reserved - so DynamoDB won't like them in the UpdateExpressions list.
  // To avoid passing reserved words we prefix each field with "#field" and provide the correct
  // field mapping in ExpressionAttributeNames. The same has to be done with the actual
  // value as well. They are prefixed with ":value" and mapped in ExpressionAttributeValues
  // along witht heir actual value
  const { Attributes } = await client.send(new UpdateItemCommand({
    TableName: tableName,
    Key: marshall(key),
    ReturnValues: 'ALL_NEW',
    UpdateExpression: `SET ${itemKeys.map((k, index) => `#field${index} = :value${index}`).join(', ')}`,
    ExpressionAttributeNames: itemKeys.reduce((accumulator, k, index) => ({ ...accumulator, [`#field${index}`]: k }), {}),
    ExpressionAttributeValues: marshall(itemKeys.reduce((accumulator, k, index) => ({ ...accumulator, [`:value${index}`]: item[k] }), {})),
  }));

  return unmarshall(Attributes);
};