DynamoDB中使用UpdateExpression的SET递增字段失败问题
问题描述
我正依照AWS文档,基于NodeJS SDK v3实现Lambda函数,对DynamoDB中的标量字段进行递增操作。但使用UpdateExpression中的SET命令递增字段时出现问题。
命令初始化与执行示例
const params = { TableName: 'MyTable', Key: { id: 'my-id' }, ExpressionAttributeNames: { '#credit': 'user.credit', }, ExpressionAttributeValues: { ':creditToAdd': 100, }, UpdateExpression: 'SET #credit = #credit + :creditToAdd', ReturnValues: 'ALL_NEW' }; const client = new DynamoDBClient(options); const docClient = new DynamoDBDocumentClient(client); const command = new UpdateCommand(params); const updateUserResponse = await docClient.send(command);
报错信息
ValidationException: The provided expression refers to an attribute that does not exist in the item
测试情况
- 使用直接赋值的UpdateExpression无问题:
UpdateExpression: 'SET #credit = :creditToAdd', - 改用
ADD语法可正常运行:UpdateExpression: 'ADD #credit :creditToAdd',
但AWS文档提到:
In general, we recommend using SET rather than ADD.
且我更倾向于使用SET来结合其他字段更新(如最后充值时间戳),请问我哪里操作有误?
解决方案
问题出在嵌套属性不存在时,DynamoDB无法直接对其执行算术运算:
- 当你用
SET #credit = :creditToAdd时,DynamoDB会自动创建不存在的嵌套属性(比如user对象和credit字段)并赋值; - 但用
SET #credit = #credit + :creditToAdd时,如果user.credit(甚至user)不存在,DynamoDB找不到运算的左值,就会抛出属性不存在的错误; ADD语法之所以能正常运行,是因为它会自动将不存在的属性初始化为0再执行递增操作。
要解决这个问题,你可以使用DynamoDB的if_not_exists()函数,为不存在的属性设置默认值后再做运算。修改后的代码示例如下:
const params = { TableName: 'MyTable', Key: { id: 'my-id' }, ExpressionAttributeNames: { '#credit': 'user.credit', '#lastRecharge': 'user.lastRecharge' // 新增的字段示例 }, ExpressionAttributeValues: { ':creditToAdd': 100, ':zero': 0, ':currentTime': Date.now() // 时间戳示例 }, UpdateExpression: ` SET #credit = if_not_exists(#credit, :zero) + :creditToAdd, #lastRecharge = :currentTime `, ReturnValues: 'ALL_NEW' }; // 后续客户端初始化与执行代码不变 const client = new DynamoDBClient(options); const docClient = new DynamoDBDocumentClient(client); const command = new UpdateCommand(params); const updateUserResponse = await docClient.send(command);
说明
if_not_exists(#credit, :zero)会检查user.credit是否存在:如果存在则返回其当前值,不存在则返回:zero(即0);- 这样无论属性是否存在,都能正常执行加法运算,同时还能在同一个UpdateExpression中添加其他字段的更新操作(比如示例中的
lastRecharge时间戳); - 完全符合AWS文档推荐使用SET的要求,也满足你结合多字段更新的需求。
内容的提问来源于stack exchange,提问作者mangelsnc
相关产品推荐
相关产品推荐

