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

5
  • What do you mean by "When an argument goes missing"? Commented Jul 9, 2020 at 4:41
  • 1
    Also, An expression attribute name must begin with a pound sign (#), docs.aws.amazon.com/amazondynamodb/latest/developerguide/… Commented Jul 9, 2020 at 4: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 ? Commented Jul 10, 2020 at 7:02
  • Please update your question with correct formatting. Hoping someone else will chime in with a more elegant solution Commented Jul 10, 2020 at 19:40
  • @LucasD Sure I will re format the question. Thanks for your answer. I will try it and update in here. :) Commented Jul 11, 2020 at 3:07

2 Answers 2

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,
  };
Sign up to request clarification or add additional context in comments.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.