Amazon DocumentDB 文档更新 #

一、更新方法概述 #

1.1 更新方法 #

text
更新方法:
├── updateOne - 更新单个文档
├── updateMany - 更新多个文档
├── replaceOne - 替换整个文档
├── findOneAndUpdate - 查找并更新
└── findOneAndReplace - 查找并替换

1.2 更新操作符 #

text
常用更新操作符:
├── 字段操作符
│   ├── $set - 设置字段值
│   ├── $unset - 删除字段
│   ├── $setOnInsert - 插入时设置
│   ├── $inc - 数值增减
│   ├── $mul - 数值乘法
│   ├── $rename - 重命名字段
│   ├── $min - 取最小值
│   └── $max - 取最大值
│
├── 数组操作符
│   ├── $push - 添加元素
│   ├── $pull - 删除元素
│   ├── $addToSet - 添加唯一元素
│   ├── $pop - 删除首尾元素
│   └── $pullAll - 删除多个元素
│
└── 位操作符
    ├── $bit - 位运算
    └── $ - 更新第一个匹配元素

二、updateOne - 更新单个文档 #

2.1 基本用法 #

javascript
// 更新单个文档
db.users.updateOne(
  { name: "张三" },
  { $set: { age: 31, city: "上海" } }
)

// 返回结果
{
  "acknowledged": true,
  "matchedCount": 1,
  "modifiedCount": 1
}

2.2 $set操作符 #

javascript
// 设置字段值
db.users.updateOne(
  { _id: ObjectId("...") },
  { $set: { 
    name: "张三",
    age: 31,
    "address.city": "上海"
  }}
)

// 设置嵌套字段
db.users.updateOne(
  { name: "张三" },
  { $set: { "address.province": "上海" } }
)

2.3 $unset操作符 #

javascript
// 删除字段
db.users.updateOne(
  { name: "张三" },
  { $unset: { tempField: "", deprecatedField: "" } }
)

2.4 $inc操作符 #

javascript
// 数值增减
db.products.updateOne(
  { _id: 1 },
  { $inc: { stock: -1, viewCount: 1 } }
)

// 增加多个字段
db.users.updateOne(
  { name: "张三" },
  { $inc: { loginCount: 1, score: 10 } }
)

2.5 $mul操作符 #

javascript
// 数值乘法
db.products.updateOne(
  { _id: 1 },
  { $mul: { price: 1.1 } }  // 价格增加10%
)

2.6 $rename操作符 #

javascript
// 重命名字段
db.users.updateOne(
  { name: "张三" },
  { $rename: { "oldName": "newName", "addr": "address" } }
)

2.7 $min和$max操作符 #

javascript
// 设置最小值
db.products.updateOne(
  { _id: 1 },
  { $min: { price: 50 } }  // 如果当前价格>50,则更新为50
)

// 设置最大值
db.products.updateOne(
  { _id: 1 },
  { $max: { stock: 100 } }  // 如果当前库存<100,则更新为100
)

2.8 $setOnInsert操作符 #

javascript
// 仅在插入时设置(配合upsert使用)
db.users.updateOne(
  { email: "new@example.com" },
  {
    $set: { name: "新用户", updatedAt: new Date() },
    $setOnInsert: { createdAt: new Date() }
  },
  { upsert: true }
)

三、updateMany - 更新多个文档 #

3.1 基本用法 #

javascript
// 更新多个文档
db.users.updateMany(
  { status: "pending" },
  { $set: { status: "active", updatedAt: new Date() } }
)

// 返回结果
{
  "acknowledged": true,
  "matchedCount": 100,
  "modifiedCount": 100
}

3.2 批量更新示例 #

javascript
// 批量更新状态
db.orders.updateMany(
  { 
    status: "processing",
    createdAt: { $lt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) }
  },
  { $set: { status: "timeout" } }
)

// 批量增加字段
db.products.updateMany(
  { category: "electronics" },
  { $set: { warranty: "1年" } }
)

// 批量删除字段
db.users.updateMany(
  {},
  { $unset: { deprecatedField: "" } }
)

四、数组更新操作 #

4.1 $push操作符 #

javascript
// 添加数组元素
db.users.updateOne(
  { name: "张三" },
  { $push: { tags: "新标签" } }
)

// 添加多个元素
db.users.updateOne(
  { name: "张三" },
  { $push: { 
    scores: { $each: [90, 85, 88] }
  }}
)

// 带排序和限制
db.users.updateOne(
  { name: "张三" },
  { $push: {
    grades: {
      $each: [85, 90, 88],
      $sort: -1,
      $slice: 5  // 只保留前5个
    }
  }}
)

// 添加到指定位置
db.users.updateOne(
  { name: "张三" },
  { $push: {
    items: {
      $each: ["item1", "item2"],
      $position: 0  // 插入到开头
    }
  }}
)

4.2 $pull操作符 #

javascript
// 删除匹配元素
db.users.updateOne(
  { name: "张三" },
  { $pull: { tags: "旧标签" } }
)

// 条件删除
db.users.updateOne(
  { name: "张三" },
  { $pull: { scores: { $lt: 60 } } }  // 删除小于60的分数
)

// 删除嵌套数组元素
db.users.updateOne(
  { name: "张三" },
  { $pull: { "comments": { status: "deleted" } } }
)

4.3 $pullAll操作符 #

javascript
// 删除多个指定元素
db.users.updateOne(
  { name: "张三" },
  { $pullAll: { tags: ["标签1", "标签2", "标签3"] } }
)

4.4 $addToSet操作符 #

javascript
// 添加唯一元素(不存在才添加)
db.users.updateOne(
  { name: "张三" },
  { $addToSet: { tags: "编程" } }
)

// 添加多个唯一元素
db.users.updateOne(
  { name: "张三" },
  { $addToSet: { 
    tags: { $each: ["阅读", "游泳", "编程"] }
  }}
)

4.5 $pop操作符 #

javascript
// 删除最后一个元素
db.users.updateOne(
  { name: "张三" },
  { $pop: { tags: 1 } }
)

// 删除第一个元素
db.users.updateOne(
  { name: "张三" },
  { $pop: { tags: -1 } }
)

4.6 $位置操作符 #

javascript
// 更新第一个匹配的数组元素
db.users.updateOne(
  { "grades.subject": "数学" },
  { $set: { "grades.$.score": 95 } }
)

// 使用arrayFilters
db.users.updateOne(
  { name: "张三" },
  { $set: { "grades.$[elem].passed": true } },
  { arrayFilters: [{ "elem.score": { $gte: 60 } }] }
)

五、replaceOne - 替换文档 #

5.1 基本用法 #

javascript
// 替换整个文档(保留_id)
db.users.replaceOne(
  { _id: ObjectId("...") },
  {
    name: "张三",
    age: 31,
    email: "zhangsan@example.com",
    city: "上海"
  }
)

// 返回结果
{
  "acknowledged": true,
  "matchedCount": 1,
  "modifiedCount": 1
}

5.2 与updateOne的区别 #

javascript
// updateOne - 只更新指定字段
db.users.updateOne(
  { name: "张三" },
  { $set: { age: 31 } }
)
// 结果:其他字段保留

// replaceOne - 替换整个文档
db.users.replaceOne(
  { name: "张三" },
  { name: "张三", age: 31 }
)
// 结果:只有name和age字段,其他字段被删除

六、findOneAndUpdate #

6.1 基本用法 #

javascript
// 查找并更新,返回更新前的文档
const result = db.users.findOneAndUpdate(
  { name: "张三" },
  { $inc: { loginCount: 1 } }
)

// 返回更新前的文档
{
  "_id": ObjectId("..."),
  "name": "张三",
  "loginCount": 5
}

6.2 返回更新后的文档 #

javascript
// 返回更新后的文档
const result = db.users.findOneAndUpdate(
  { name: "张三" },
  { $inc: { loginCount: 1 } },
  { returnDocument: "after" }
)

// 返回更新后的文档
{
  "_id": ObjectId("..."),
  "name": "张三",
  "loginCount": 6
}

6.3 其他选项 #

javascript
// 完整选项
const result = db.users.findOneAndUpdate(
  { email: "new@example.com" },
  { $set: { name: "新用户", createdAt: new Date() } },
  {
    returnDocument: "after",
    upsert: true,
    sort: { createdAt: -1 },
    projection: { name: 1, email: 1 }
  }
)

七、upsert操作 #

7.1 基本用法 #

javascript
// 如果存在则更新,不存在则插入
db.users.updateOne(
  { email: "zhangsan@example.com" },
  { $set: { name: "张三", age: 30 } },
  { upsert: true }
)

// 返回结果
{
  "acknowledged": true,
  "matchedCount": 0,
  "modifiedCount": 0,
  "upsertedId": ObjectId("...")
}

7.2 upsert应用场景 #

javascript
// 用户登录计数
db.users.updateOne(
  { userId: "user123" },
  {
    $inc: { loginCount: 1 },
    $set: { lastLogin: new Date() },
    $setOnInsert: { createdAt: new Date() }
  },
  { upsert: true }
)

// 页面访问统计
db.pageStats.updateOne(
  { page: "/home" },
  { $inc: { views: 1 } },
  { upsert: true }
)

八、原子操作 #

8.1 条件更新 #

javascript
// 使用条件表达式
db.products.updateOne(
  { 
    _id: 1,
    stock: { $gte: 1 }  // 只有库存>=1时才更新
  },
  { $inc: { stock: -1 } }
)

// 返回结果检查
if (result.modifiedCount === 0) {
  print("库存不足");
}

8.2 乐观锁 #

javascript
// 使用版本号实现乐观锁
function updateWithOptimisticLock(docId, updateFn) {
  let retries = 3;
  
  while (retries > 0) {
    const doc = db.users.findOne({ _id: docId });
    const newVersion = doc.version + 1;
    
    const result = db.users.updateOne(
      { 
        _id: docId, 
        version: doc.version 
      },
      {
        $set: updateFn(doc),
        $inc: { version: 1 }
      }
    );
    
    if (result.modifiedCount === 1) {
      return true;
    }
    
    retries--;
  }
  
  return false;
}

8.3 原子计数器 #

javascript
// 获取并递增计数器
function getNextSequence(name) {
  const result = db.counters.findOneAndUpdate(
    { _id: name },
    { $inc: { seq: 1 } },
    { 
      returnDocument: "after",
      upsert: true
    }
  );
  
  return result.seq;
}

// 使用示例
const orderId = getNextSequence("order_id");
db.orders.insertOne({
  _id: orderId,
  items: [...]
});

九、更新选项 #

9.1 写关注 #

javascript
// 设置写关注
db.users.updateOne(
  { name: "张三" },
  { $set: { age: 31 } },
  { writeConcern: { w: "majority", j: true } }
)

9.2 数组过滤器 #

javascript
// 使用arrayFilters更新特定数组元素
db.users.updateOne(
  { name: "张三" },
  { $set: { "grades.$[elem].passed": true } },
  { 
    arrayFilters: [
      { "elem.score": { $gte: 60 } }
    ]
  }
)

9.3 排序选项 #

javascript
// findOneAndUpdate中使用排序
db.users.findOneAndUpdate(
  { status: "pending" },
  { $set: { status: "processing" } },
  { sort: { priority: -1 } }
)

十、性能优化 #

10.1 索引使用 #

javascript
// 确保更新条件使用索引
db.users.createIndex({ email: 1 })

// 更新时使用索引字段
db.users.updateOne(
  { email: "zhangsan@example.com" },
  { $set: { lastLogin: new Date() } }
)

10.2 批量更新优化 #

javascript
// 使用updateMany代替循环updateOne
// 不推荐
db.users.find({ status: "pending" }).forEach(user => {
  db.users.updateOne(
    { _id: user._id },
    { $set: { status: "active" } }
  );
});

// 推荐
db.users.updateMany(
  { status: "pending" },
  { $set: { status: "active" } }
)

10.3 更新操作优化 #

text
优化建议:
├── 使用索引字段作为更新条件
├── 避免全文档替换
├── 使用$inc代替读取-计算-写入
├── 批量更新使用updateMany
└── 合理设置写关注

十一、最佳实践 #

11.1 更新策略 #

text
更新最佳实践:
├── 使用$set只更新必要字段
├── 使用$inc进行原子计数
├── 使用upsert实现插入或更新
├── 使用条件更新实现乐观锁
└── 处理更新失败情况

11.2 错误处理 #

javascript
// 完整的错误处理
try {
  const result = db.users.updateOne(
    { _id: ObjectId("...") },
    { $set: { status: "active" } }
  );
  
  if (result.matchedCount === 0) {
    print("文档不存在");
  } else if (result.modifiedCount === 0) {
    print("文档未修改");
  } else {
    print("更新成功");
  }
} catch (error) {
  print("更新错误: " + error.message);
}

十二、总结 #

12.1 更新方法对比 #

方法 用途 返回值
updateOne 更新单个文档 更新结果
updateMany 更新多个文档 更新结果
replaceOne 替换整个文档 更新结果
findOneAndUpdate 查找并更新 文档

12.2 操作符速查 #

操作符 用途
$set 设置字段值
$unset 删除字段
$inc 数值增减
$push 添加数组元素
$pull 删除数组元素
$addToSet 添加唯一元素

下一步,让我们学习文档删除!

最后更新:2026-03-27