Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically update an attribute in a dynamodb item?

I created an item in dynamodb using Node js, the item has multiple attributes such as brand, category, discount, validity, etc. I am using uuid to generate ids for each item. Now let's say I want to update the validity attribute of the item, in which case I am currently sending the entire json object with the value of validity modified to the new value.

This is definitely not optimal, please help me find an optimal solution.

const params = {
    TableName: process.env.PRODUCT_TABLE,
    Key: {
      id: event.pathParameters.id,
    },
    ExpressionAttributeNames: {
      '#discount': 'discount',
    },
    ExpressionAttributeValues: {
      ':brand': data.brand,
      ':category': data.category,
      ':discount': data.discount,
      ':denominations': data.denominations,
      ":validity": data.validity,
      ":redemption": data.redemption    
    },
    UpdateExpression: 'SET #discount = :discount, denominations = :denominations, brand = :brand, category = :category, validity = :validity, redemption = :redemption',
    ReturnValues: 'ALL_NEW',
  };

I want to send just the attribute I want to update with the new value, if I want to change the validity from 6 months to 8 months, I should just send something like: { "validity": "8 months" } And it should update the validity attribute of the item. Same should apply to any other attribute of the item.

'use strict';

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

const dynamoDb = new AWS.DynamoDB.DocumentClient();

module.exports.update = (event, context, callback) => {
  const data = JSON.parse(event.body);

  let attr = {};
  let nameobj = {};
  let exp = 'SET #';
  let arr = Object.keys(data);
  let attrname = {};

  arr.map((key) => {attr[`:${key}`]=data[key]});

  arr.map((key) => {
    exp += `${key} = :${key}, `
  });

  arr.map((key) => {nameobj[`#${key}`]=data[key]});

  attrname = {
    [Object.keys(nameobj)[0]] : nameobj[Object.keys(nameobj)[0]]
  }

  const params = {
    TableName: process.env.PRODUCT_TABLE,
    Key: {
      id: event.pathParameters.id,
    },
    ExpressionAttributeNames: attrname,
    ExpressionAttributeValues: attr,
    UpdateExpression: exp,
    ReturnValues: 'ALL_NEW',
  };

  // update the todo in the database
  dynamoDb.update(params, (error, result) => {
    // handle potential errors
    if (error) {
      console.error(error);
      callback(null, {
        statusCode: error.statusCode || 501,
        headers: { 'Content-Type': 'text/plain' },
        body: 'Couldn\'t update the card',
      });
      return;
    }

    // create a response
    const response = {
      statusCode: 200,
      body: JSON.stringify(result.Attributes),
    };
    callback(null, response);
  });
};
like image 847
Deb Avatar asked Apr 24 '19 08:04

Deb


People also ask

How do I update a DynamoDB item?

To update an existing item in an Amazon DynamoDB table, you use the UpdateItem operation. You must provide the key of the item that you want to update. You must also provide an update expression, indicating the attributes that you want to modify and the values that you want to assign to them.

What is the difference between put and update in DynamoDB?

The main difference between the two is, PutItem will Replace an entire item while UpdateItem will Update it. Eg. This will replace Name and Gender and now new Item is UserId and Country. While if you want to update an item from Name = ABC to Name = 123 you have to use UpdateItem .

What is the relationship between an attribute item and table in Amazon DynamoDB?

In DynamoDB, tables, items, and attributes are the core components that you work with. A table is a collection of items, and each item is a collection of attributes. DynamoDB uses primary keys to uniquely identify each item in a table and secondary indexes to provide more querying flexibility.

Can we update range key in DynamoDB?

You can use UpdateItem to update any nonkey attributes. Show activity on this post.


1 Answers

Contrary to others comments, this is very possible, use the UpdateItem action.

Language agnostic API docs

JavaScript specific API docs

If you want to dynamically create the query, try something like this:

const generateUpdateQuery = (fields) => {
    let exp = {
        UpdateExpression: 'set',
        ExpressionAttributeNames: {},
        ExpressionAttributeValues: {}
    }
    Object.entries(fields).forEach(([key, item]) => {
        exp.UpdateExpression += ` #${key} = :${key},`;
        exp.ExpressionAttributeNames[`#${key}`] = key;
        exp.ExpressionAttributeValues[`:${key}`] = item
    })
    exp.UpdateExpression = exp.UpdateExpression.slice(0, -1);
    return exp
}

let data = {
    'field' : { 'subfield': 123 },
    'other': '456'
}

let expression = generateUpdateQuery(data)

let params = {
    // Key, Table, etc..
    ...expression
}

console.log(params)

Output:

{ 
    UpdateExpression: 'set #field = :field, #other = :other',
    ExpressionAttributeNames: {
        '#field': 'field',
        '#other': 'other'
    },
    ExpressionAttributeValues: {
        ':field': { 
            'subfield': 123
        },
        ':other': '456'
    } 
}
like image 57
Richard Dunn Avatar answered Sep 22 '22 22:09

Richard Dunn