1

I am trying to update my existing record in my dynamodb table. Like below I have an Item in my table

let params = {
   TableName: proces.env.dynamoDbTable,
   Item: {
      productId: "id",
      att1: val1,
      att2: val2
      }
 }

I want to perform an update. I am using the aws dynamodb sdk's update method and passing it params like below

let aws = require('aws-sdk');
 let dbb = new aws.DynamoDb.DocumentClient();
 let params = {
  TableName: process.env.tableName,
  Key: {productID}
  ExpressionAttributeNames: { "#updatedAt" : "updatedAt" }
  ExpressionAttributeValues: {":u":moment().unix(), ":val1" : a, ":val2": b}
  UpdateExpression: "SET att1 = :val1, att2: val2, #updatedAt: :u"
 }
// a, b are passed as argument to function and are optional
dbb.update(params).promise()

When an argument goes missing the dynamo raises ExpressionAttributeValue missing exception and I know it is straight. Is there a way I can update my Item with the attributes provided

timer_1995
  • 13
  • 5
  • What do you mean by "When an argument goes missing"? – Lucas D Jul 09 '20 at 04:41
  • 1
    Also, `An expression attribute name must begin with a pound sign (#),` https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ExpressionAttributeNames.html – Lucas D Jul 09 '20 at 04:43
  • @LucasD Here's what my update expression looks like "SET #name =:n, #slug = :s, #updatedAt = :u,description= :d, thumbnail= :t" I receive a req from front end to update a param called "description". When I call update method, It throws me a code "ValidationException" missing attribute values :n. I understand that Since I haven't passed value the error is expected. How can I do update only few attributes I receive and leave the rest intact ? – timer_1995 Jul 10 '20 at 07:02
  • Please update your question with correct formatting. Hoping someone else will chime in with a more elegant solution – Lucas D Jul 10 '20 at 19:40
  • @LucasD Sure I will re format the question. Thanks for your answer. I will try it and update in here. :) – timer_1995 Jul 11 '20 at 03:07

2 Answers2

2

Unfortunately dynamodb does not make this easy. But you can use some fancy js to create the params object dynamically:

  // for some object `attrs` we find which keys we need to update
  const keys = Object.keys(attrs);
  const values = Object.values(attrs);

  // get a list of key names and value names to match the dynamodb syntax
  const attributeKeyNames = keys.map((k) => '#key_' + k);
  const attributeValueNames = keys.map((k) => ':val_' + k);

  // create individual expressions for each attribute that needs to be updated
  const expressions = attributeValueNames.map((attr, i) => {
    return `${attributeKeyNames[i]} = ${attr}`;
  });

  // add the SET keyword to the beginning of the string
  // and join all the expressions with a comma
  const UpdateExpression = 'SET ' + expressions.join(', ');

  // I use `zipObject()` from lodash https://lodash.com/docs/4.17.15#zipObject
  // it makes an object map from two arrays where the first is the keys and
  // the second is the values
  const ExpressionAttributeValues = _.zipObject(attributeValueNames, values);
  const ExpressionAttributeNames = _.zipObject(attributeKeyNames, keys);

  // now you have all the params
  const params = {
    TableName,
    Key: {
      uuid,
    },
    UpdateExpression,
    ExpressionAttributeValues,
    ExpressionAttributeNames,
  };
Lucas D
  • 460
  • 1
  • 4
  • 15
0

Lucas D's answer works great. A couple of things to keep in mind though:

If you're sending an object with a unique key into your update function, you must remove that key before mapping your expression arrays or it will be included in the query and will get an error:

const newObject = {...originalObject}
delete newObject.unique_key

If you can't or don't want to use Lodash, you can use Object.assign to map your keys/values arrays:

const ExpressionAttributeValues = Object.assign(...attributeValueNames.map((k, i) => ({[k]: values[i]})));
const ExpressionAttributeNames = Object.assign(...attributeKeyNames.map((k, i) => ({[k]: keys[i]})));
FX2000
  • 141
  • 6