Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DynamoDB: UpdateItem, Ignore Null values in ExpressionAttributeValues

I'm using DynamoDB UpdateItem to update records in my DB. A basic function like this is working for me.

var user = {
    userID: '123213',
    name: 'John Doe',
    age: 12,
    type: 'creator'
};
var params = {
    TableName:table,
    Key:{
        "UserID": user.userID
    },
    UpdateExpression: "set Name = :r, Age=:p, Type=:a",
    ExpressionAttributeValues:{
        ":r":user.name,
        ":p":user.age,
        ":a":user.type
    },
    ReturnValues:"UPDATED_NEW"
};

docClient.update(params, function(err, data) {
    if (err) {
        console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
    } else {
        console.log("UpdateItem succeeded:", JSON.stringify(data, null, 2));
    }
});

But...

If I'd like to only update one attribute, the name, like this:

 var user = {
        userID: '123213',
        name: 'John Smith'
    };
var params = {
    TableName:table,
    Key:{
        "UserID": user.userID
    },
    UpdateExpression: "set Name = :r, Age=:p, Type=:a",
    ExpressionAttributeValues:{
        ":r":user.name,
        ":p":user.age,
        ":a":user.type
    },
    ReturnValues:"UPDATED_NEW"
};

It gives me the error that

ExpressionAttributeValues cannot be NULL.

I know that I could dynamically produce the UpdateExpression String by checking for values in user, like this:

for (var key in user) {
  if (user.hasOwnProperty(key)) {
    ...add to DynamicUpdateExpression..
  }
}

but is there a way that I can tell updateItem to ignore the null values and only update the name?

like image 943
Abdullah Rasheed Avatar asked Aug 23 '17 14:08

Abdullah Rasheed


1 Answers

This is a much simpler answer.

It works when you consider ExpressionAttributeValues an object.

Here's the code:

params.TableName = ddbTable;
params.UpdateExpression =  "set LastPostedDateTime = :l" ;
if (req.body.AttachmentDescription)  { params.UpdateExpression  += ", AttachmentDescription = :d"; }
if (req.body.AttachmentURL)          { params.UpdateExpression  += ", AttachmentURL = :a"; }

so first we build up the expression if values are available to be passed, using a simple concatenation technique.

Then we supply the values:

params.ExpressionAttributeValues = {};
params.ExpressionAttributeValues[':l'] =  formattedDate ;
if (req.body.AttachmentDescription)  { params.ExpressionAttributeValues[':d']= req.body.AttachmentDescription ; }
if (req.body.AttachmentURL)          { params.ExpressionAttributeValues[':a']= req.body.AttachmentURL ; }

The difficulty is with ExpressionAttributeValues which here, we treat as an object and we can add to the object if we first define it as an object, hence the {}.

Then if the object does not already have the property name it adds it and then adds the value.

The net result is you can have very wide flat records as your records can be extended with variable field names. I.e. this application lists a URL and descriptor. With variable field names, I could add more URLs and descriptors to the same record. There is ultimately a memory limit, yet this type of application, for a few variable fields, would be sufficient for my application.

like image 200
David White Avatar answered Oct 09 '22 19:10

David White