DynamoDB更新数据 #
一、UpdateItem概述 #
1.1 基本概念 #
UpdateItem 用于更新项目中的属性,可添加、修改或删除属性。
text
UpdateItem特点:
├── 部分更新属性
├── 项目不存在时创建
├── 支持原子操作
├── 支持条件表达式
└── 支持返回值
1.2 与PutItem区别 #
| 操作 | 行为 | 适用场景 |
|---|---|---|
| PutItem | 完全替换项目 | 创建或完全替换 |
| UpdateItem | 部分更新属性 | 修改部分属性 |
二、更新表达式 #
2.1 SET操作 #
SET用于添加或修改属性:
bash
aws dynamodb update-item \
--table-name Users \
--key '{"UserId": {"S": "user123"}}' \
--update-expression 'SET Name = :name, Age = :age' \
--expression-attribute-values \
'{":name": {"S": "John Smith"}, ":age": {"N": "31"}}'
javascript
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Name = :name, Age = :age',
ExpressionAttributeValues: {
':name': 'John Smith',
':age': 31
}
}));
2.2 REMOVE操作 #
REMOVE用于删除属性:
bash
aws dynamodb update-item \
--table-name Users \
--key '{"UserId": {"S": "user123"}}' \
--update-expression 'REMOVE TempField, OldField'
javascript
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'REMOVE TempField, OldField'
}));
2.3 ADD操作 #
ADD用于添加到集合或数字增量:
bash
# 数字增量
aws dynamodb update-item \
--table-name Counters \
--key '{"CounterId": {"S": "visits"}}' \
--update-expression 'ADD Value :inc' \
--expression-attribute-values '{":inc": {"N": "1"}}'
# 添加到集合
aws dynamodb update-item \
--table-name Users \
--key '{"UserId": {"S": "user123"}}' \
--update-expression 'ADD Tags :tag' \
--expression-attribute-values '{":tag": {"SS": ["new_tag"]}}'
javascript
// 数字增量
await docClient.send(new UpdateCommand({
TableName: 'Counters',
Key: { CounterId: 'visits' },
UpdateExpression: 'ADD Value :inc',
ExpressionAttributeValues: { ':inc': 1 }
}));
// 添加到集合
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'ADD Tags :tag',
ExpressionAttributeValues: {
':tag': new Set(['new_tag'])
}
}));
2.4 DELETE操作 #
DELETE用于从集合中删除元素:
bash
aws dynamodb update-item \
--table-name Users \
--key '{"UserId": {"S": "user123"}}' \
--update-expression 'DELETE Tags :tag' \
--expression-attribute-values '{":tag": {"SS": ["old_tag"]}}'
javascript
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'DELETE Tags :tag',
ExpressionAttributeValues: {
':tag': new Set(['old_tag'])
}
}));
三、高级更新操作 #
3.1 原子计数器 #
javascript
// 增加计数器
const response = await docClient.send(new UpdateCommand({
TableName: 'Counters',
Key: { CounterId: 'page_views' },
UpdateExpression: 'SET #v = #v + :inc',
ExpressionAttributeNames: {
'#v': 'Value'
},
ExpressionAttributeValues: {
':inc': 1
},
ReturnValues: 'UPDATED_NEW'
}));
console.log('New value:', response.Attributes.Value);
3.2 条件更新 #
javascript
// 仅当版本匹配时更新
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Name = :name, Version = Version + :inc',
ConditionExpression: 'Version = :currentVersion',
ExpressionAttributeValues: {
':name': 'John Smith',
':inc': 1,
':currentVersion': 5
}
}));
3.3 列表操作 #
更新列表元素:
javascript
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Tags[0] = :tag',
ExpressionAttributeValues: {
':tag': 'updated_tag'
}
}));
追加到列表:
javascript
// 追加到末尾
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Tags = list_append(Tags, :newTags)',
ExpressionAttributeValues: {
':newTags': ['tag4', 'tag5']
}
}));
// 追加到开头
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Tags = list_append(:newTags, Tags)',
ExpressionAttributeValues: {
':newTags': ['tag0']
}
}));
从列表中删除元素:
javascript
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'REMOVE Tags[1], Tags[2]'
}));
3.4 嵌套属性更新 #
javascript
// 更新嵌套Map属性
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Address.City = :city, Address.Country = :country',
ExpressionAttributeValues: {
':city': 'Shanghai',
':country': 'China'
}
}));
// 更新深层嵌套属性
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Profile.Contacts.Email = :email',
ExpressionAttributeValues: {
':email': 'newemail@example.com'
}
}));
3.5 条件创建属性 #
javascript
// 仅当属性不存在时设置
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET CreatedAt = if_not_exists(CreatedAt, :now)',
ExpressionAttributeValues: {
':now': new Date().toISOString()
}
}));
四、表达式属性名 #
4.1 处理保留字 #
DynamoDB有保留字,使用ExpressionAttributeNames处理:
javascript
// "Name"是保留字
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET #n = :name, #s = :status',
ExpressionAttributeNames: {
'#n': 'Name',
'#s': 'Status'
},
ExpressionAttributeValues: {
':name': 'John Smith',
':status': 'active'
}
}));
4.2 常见保留字 #
text
常见保留字:
├── Name, Names
├── Status
├── Date
├── Year, Month, Day
├── User
├── Order
├── Key, Value
├── Data
└── Timestamp
五、返回值配置 #
5.1 返回选项 #
| 选项 | 说明 |
|---|---|
| NONE | 不返回任何值(默认) |
| ALL_OLD | 返回更新前的完整项目 |
| UPDATED_OLD | 返回更新前被修改的属性 |
| ALL_NEW | 返回更新后的完整项目 |
| UPDATED_NEW | 返回更新后被修改的属性 |
5.2 使用示例 #
javascript
// 返回更新后的属性
const response = await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Name = :name, Age = :age',
ExpressionAttributeValues: {
':name': 'John Smith',
':age': 31
},
ReturnValues: 'UPDATED_NEW'
}));
console.log('Updated attributes:', response.Attributes);
// { Name: 'John Smith', Age: 31 }
javascript
// 返回更新前的值
const response = await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Name = :name',
ExpressionAttributeValues: { ':name': 'John Smith' },
ReturnValues: 'ALL_OLD'
}));
console.log('Old item:', response.Attributes);
// { UserId: 'user123', Name: 'John Doe', Age: 30, ... }
六、条件表达式 #
6.1 常用条件 #
javascript
// 属性存在检查
ConditionExpression: 'attribute_exists(Email)'
// 属性不存在检查
ConditionExpression: 'attribute_not_exists(DeletedAt)'
// 值比较
ConditionExpression: 'Age > :minAge'
ConditionExpression: 'Status = :status'
ConditionExpression: 'Version = :expectedVersion'
// 集合包含
ConditionExpression: 'contains(Tags, :tag)'
// 大小检查
ConditionExpression: 'size(Description) <= :maxSize'
// 组合条件
ConditionExpression: 'Status = :status AND Age > :minAge'
6.2 乐观锁实现 #
javascript
async function updateUserWithOptimisticLock(userId, updates, currentVersion) {
try {
const response = await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: userId },
UpdateExpression: 'SET #n = :name, Version = Version + :inc',
ConditionExpression: 'Version = :currentVersion',
ExpressionAttributeNames: {
'#n': 'Name'
},
ExpressionAttributeValues: {
':name': updates.name,
':inc': 1,
':currentVersion': currentVersion
},
ReturnValues: 'ALL_NEW'
}));
return { success: true, item: response.Attributes };
} catch (error) {
if (error.name === 'ConditionalCheckFailedException') {
return { success: false, error: 'Version conflict - item was modified by another process' };
}
throw error;
}
}
七、实用示例 #
7.1 用户状态更新 #
javascript
async function updateUserStatus(userId, newStatus) {
const timestamp = new Date().toISOString();
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: userId },
UpdateExpression: `
SET #s = :status,
UpdatedAt = :timestamp,
StatusHistory = list_append(if_not_exists(StatusHistory, :emptyList), :newEntry)
`,
ExpressionAttributeNames: {
'#s': 'Status'
},
ExpressionAttributeValues: {
':status': newStatus,
':timestamp': timestamp,
':emptyList': [],
':newEntry': [{ status: newStatus, timestamp }]
}
}));
}
7.2 购物车更新 #
javascript
async function addToCart(userId, product) {
const { productId, name, price, quantity } = product;
await docClient.send(new UpdateCommand({
TableName: 'Carts',
Key: { UserId: userId },
UpdateExpression: `
SET Items = if_not_exists(Items, :emptyList),
TotalPrice = if_not_exists(TotalPrice, :zero) + :priceIncrease,
UpdatedAt = :timestamp
ADD Items[${getInsertIndex()}] :newItem
`,
ExpressionAttributeValues: {
':emptyList': [],
':zero': 0,
':priceIncrease': price * quantity,
':timestamp': new Date().toISOString(),
':newItem': { productId, name, price, quantity }
}
}));
}
7.3 点赞功能 #
javascript
async function toggleLike(userId, postId) {
const response = await docClient.send(new UpdateCommand({
TableName: 'Posts',
Key: { PostId: postId },
UpdateExpression: `
ADD LikeCount :inc
ADD LikedByUsers :userSet
`,
ConditionExpression: 'NOT contains(LikedByUsers, :userId)',
ExpressionAttributeValues: {
':inc': 1,
':userSet': new Set([userId]),
':userId': userId
},
ReturnValues: 'UPDATED_NEW'
}));
return response.Attributes.LikeCount;
}
7.4 库存扣减 #
javascript
async function decreaseStock(productId, quantity) {
try {
const response = await docClient.send(new UpdateCommand({
TableName: 'Products',
Key: { ProductId: productId },
UpdateExpression: 'SET Stock = Stock - :quantity',
ConditionExpression: 'Stock >= :quantity',
ExpressionAttributeValues: {
':quantity': quantity
},
ReturnValues: 'UPDATED_NEW'
}));
return { success: true, remainingStock: response.Attributes.Stock };
} catch (error) {
if (error.name === 'ConditionalCheckFailedException') {
return { success: false, error: 'Insufficient stock' };
}
throw error;
}
}
八、错误处理 #
8.1 常见错误 #
javascript
try {
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
UpdateExpression: 'SET Name = :name',
ExpressionAttributeValues: { ':name': 'John Smith' }
}));
} catch (error) {
switch (error.name) {
case 'ConditionalCheckFailedException':
console.error('条件检查失败');
break;
case 'ProvisionedThroughputExceededException':
console.error('超过预置吞吐量');
break;
case 'ResourceNotFoundException':
console.error('表不存在');
break;
case 'ValidationException':
console.error('参数验证失败:', error.message);
break;
default:
console.error('未知错误:', error);
}
}
九、最佳实践 #
9.1 更新表达式优化 #
text
优化建议:
├── 合并多个SET操作
├── 使用if_not_exists避免覆盖
├── 使用ExpressionAttributeNames处理保留字
└── 合理使用ReturnValues
9.2 条件更新使用场景 #
text
适用场景:
├── 乐观锁
├── 唯一性约束
├── 业务规则验证
├── 防止并发冲突
└── 数据完整性保护
十、总结 #
UpdateItem要点:
| 特性 | 说明 |
|---|---|
| SET | 添加或修改属性 |
| REMOVE | 删除属性 |
| ADD | 数字增量或集合添加 |
| DELETE | 从集合中删除元素 |
| 条件表达式 | 支持条件更新 |
| 返回值 | 支持多种返回选项 |
下一步,让我们学习删除数据!
最后更新:2026-03-27