DynamoDB:UpdateItem,忽略 ExpressionAttributeValues 中的 Null 值

Abd*_*eed 4 lambda amazon-web-services amazon-dynamodb aws-lambda

我正在使用 DynamoDB UpdateItem来更新我的数据库中的记录。像这样的基本功能对我有用。

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));
    }
});
Run Code Online (Sandbox Code Playgroud)

但...

如果我只想更新一个属性,即名称,如下所示:

 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"
};
Run Code Online (Sandbox Code Playgroud)

它给了我这样的错误

ExpressionAttributeValues 不能为 NULL

我知道我可以UpdateExpression通过检查用户中的值来动态生成字符串,如下所示:

for (var key in user) {
  if (user.hasOwnProperty(key)) {
    ...add to DynamicUpdateExpression..
  }
}
Run Code Online (Sandbox Code Playgroud)

但是有没有一种方法可以告诉 updateItem 忽略空值而只更新name

Dav*_*ite 5

这是一个简单得多的答案。

当您将 ExpressionAttributeValues 视为一个对象时,它会起作用。

这是代码:

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

因此,首先我们使用简单的连接技术构建表达式,如果值可以传递。

然后我们提供值:

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 ; }
Run Code Online (Sandbox Code Playgroud)

困难在于 ExpressionAttributeValues,在这里,我们将其视为一个对象,如果我们首先将其定义为一个对象,则可以添加到该对象中,因此 {}。

然后,如果对象还没有属性名称,它会添加它,然后添加值。

最终结果是您可以拥有非常宽的平面记录,因为您的记录可以使用可变字段名称进行扩展。即这个应用程序列出了一个 URL 和描述符。使用可变字段名称,我可以向同一记录添加更多 URL 和描述符。最终会有一个内存限制,但这种类型的应用程序,对于一些变量字段,对于我的应用程序来说已经足够了。


Tom*_*elo 4

我问了同样的问题......在Java中有SaveBehavior.UPDATE_SKIP_NULL_ATTRIBUTES,但我在nodejs的aws-sdk中找不到类似的东西。

您可以使用AttributeUpdates而不是UpdateExpression来制定更简洁的解决方法:

const AWS      = require(aws-sdk);
const bluebird = require('bluebird');
const _        = require('lodash');

AWS.config.setPromisesDependency(bluebird);

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

var skipNullAttributes = (attributes) => {
  return _.omitBy(attributes, (attr) => { 
    return _.isNil(attr.Value); 
  }); 
}

var update = (id, attributes) => {
  var params = {
    TableName       : 'MyTableName',
    Key             : { id: id },
    AttributeUpdates: skipNullAttributes(attributes)
  };

  return dynamodb.update(params).promise();
}

exports.handler = (event, context, callback) => {
  var body   = JSON.parse(event.body);
  var userId = event.pathParameters.id;

  var attributes = {
    firstName: { Action: 'PUT', Value: body.firstName },
    lastName : { Action: 'PUT', Value: body.lastName  }
  };

  update(userId, attributes)
    .then((result) => console.log(result) )
    .catch((error) => console.error(error) );

  callback(null, {statusCode: 200, body: JSON.stringify({message: 'done!'})});
}
Run Code Online (Sandbox Code Playgroud)