MongoDB 更新文档完整指南
(MongoDB 8.0+,2025 年最新实践)
核心结论:
更新文档 =updateOne()/updateMany()/replaceOne()
支持原子操作、数组操作、管道更新、事务
一、核心更新命令对比
| 命令 | 匹配条件 | 更新方式 | 影响文档数 | 推荐场景 |
|---|---|---|---|---|
updateOne(filter, update) | 第一个匹配 | 修改字段 | 1 | 单条更新 |
updateMany(filter, update) | 所有匹配 | 修改字段 | N | 批量更新 |
replaceOne(filter, replacement) | 第一个匹配 | 替换整个文档 | 1 | 完全重写 |
二、基本更新示例
1. updateOne – 更新单条
use company
// 更新张三的年龄
db.employees.updateOne(
{ name: "张三" },
{ $set: { age: 31, "address.city": "上海" } }
)
// 返回:
// { acknowledged: true, matchedCount: 1, modifiedCount: 1 }
2. updateMany – 批量更新
// 所有技术部员工加薪 10%
db.employees.updateMany(
{ department: "技术部" },
{ $mul: { salary: 1.1 } }
)
// 技术部全部标记为在职
db.employees.updateMany(
{ department: "技术部" },
{ $set: { isActive: true, updatedAt: new Date() } }
)
3. replaceOne – 完全替换
// 完全替换文档(_id 不变)
db.employees.replaceOne(
{ _id: ObjectId("671f2a1b9d8e4c2a7f1b3d5e") },
{
name: "张三",
age: 31,
role: "高级工程师",
level: 10,
updatedAt: new Date()
}
)
三、更新操作符大全
| 操作符 | 用途 | 示例 |
|---|---|---|
$set | 设置字段值 | { $set: { age: 18 } } |
$unset | 删除字段 | { $unset: { temp: "" } } |
$inc | 增减数值 | { $inc: { views: 1 } } |
$mul | 乘法 | { $mul: { price: 0.9 } } |
$rename | 重命名字段 | { $rename: { old: "new" } } |
$setOnInsert | 仅在 upsert 时设置 | { $setOnInsert: { createdAt: new Date() } } |
$currentDate | 设置当前时间 | { $currentDate: { lastModified: true } } |
数组操作符
| 操作符 | 用途 |
|---|---|
$push | 添加到数组末尾 |
$pop | 删除首/尾元素 |
$pull | 按条件删除 |
$addToSet | 去重添加 |
$ | 定位数组中匹配的元素 |
// 向技能数组添加 Python(去重)
db.employees.updateOne(
{ name: "李四" },
{ $addToSet: { skills: "Python" } }
)
// 删除技能中的 SQL
db.employees.updateOne(
{ name: "李四" },
{ $pull: { skills: "SQL" } }
)
// 更新数组中第一个匹配的地址
db.employees.updateOne(
{ name: "王五", "address.city": "北京" },
{ $set: { "address.$.zip": "100001" } }
)
四、upsert(更新或插入)
// 如果不存在则插入,存在则更新年龄
db.employees.updateOne(
{ name: "赵六" },
{
$set: { age: 29 },
$setOnInsert: {
department: "市场部",
hireDate: new Date(),
createdAt: new Date()
}
},
{ upsert: true }
)
五、管道更新(Pipeline Update,4.2+)
支持复杂逻辑,如条件判断、变量引用。
// 只有当年龄 > 30 才加薪
db.employees.updateOne(
{ name: "张三" },
[
{ $set: {
salary: {
$cond: [
{ $gt: ["$age", 30] },
{ $multiply: ["$salary", 1.15] },
"$salary"
]
}
}
}
]
)
六、返回更新后的文档
// 返回更新后的完整文档
db.employees.findOneAndUpdate(
{ name: "张三" },
{ $set: { age: 32 } },
{ returnNewDocument: true }
)
// 或使用 aggregation pipeline
db.employees.findOneAndUpdate(
{ name: "张三" },
[ { $set: { age: 32, updatedAt: new Date() } } ],
{ returnDocument: "after" }
)
七、事务中更新(4.0+)
const session = db.getMongo().startSession();
session.startTransaction();
try {
db.accounts.updateOne(
{ user: "A" },
{ $inc: { balance: -100 } },
{ session }
);
db.accounts.updateOne(
{ user: "B" },
{ $inc: { balance: 100 } },
{ session }
);
session.commitTransaction();
} catch (error) {
session.abortTransaction();
throw error;
} finally {
session.endSession();
}
八、性能优化建议
| 场景 | 优化方式 |
|---|---|
| 批量更新 | 使用 updateMany + 批量过滤 |
| 高并发 | 使用 ordered: false(允许部分失败) |
| 大文档 | 避免频繁替换整个文档 |
| 索引 | 确保过滤字段有索引 |
// 批量更新(允许部分失败)
db.logs.updateMany(
{ level: "error" },
{ $set: { processed: true } },
{ ordered: false }
)
九、验证更新结果
// 查看修改统计
db.employees.updateOne(...)
// → matchedCount, modifiedCount, upsertedId
// 查看更新后数据
db.employees.find({ name: "张三" }).pretty()
// 聚合统计
db.employees.aggregate([
{ $match: { department: "技术部" } },
{ $group: { _id: null, avgAge: { $avg: "$age" } } }
])
十、GUI 工具更新文档
| 工具 | 操作 |
|---|---|
| MongoDB Compass | 文档 → Edit → 修改 JSON → Save |
| VS Code + MongoDB | 文档 → 右键 → Edit Document |
| MongoDB Atlas | 文档 → Edit |
十一、常见错误与解决方案
| 错误 | 原因 | 解决方案 |
|---|---|---|
No array filter found | 使用 $ 但无数组匹配 | 检查数组字段路径 |
Document failed validation | 违反 validator | 检查 Schema 或加 bypassDocumentValidation |
WriteConcernError | 副本集不可用 | 检查集群状态 |
ImmutableField | _id 不能修改 | 不可变字段 |
十二、完整更新脚本示例
// update_employees.js
use company
print("开始批量更新员工数据...")
// 1. 技术部员工加薪 + 更新时间
const techUpdate = db.employees.updateMany(
{ department: "技术部" },
{
$mul: { salary: 1.1 },
$set: { lastRaise: new Date() }
}
)
printjson(techUpdate)
// 2. 新员工插入(upsert)
const newHire = db.employees.updateOne(
{ name: "钱七" },
{
$set: { age: 25 },
$setOnInsert: {
department: "产品部",
hireDate: new Date(),
createdAt: new Date()
}
},
{ upsert: true }
)
printjson(newHire)
// 3. 替换离职员工信息
db.employees.replaceOne(
{ name: "孙八" },
{ name: "孙八", status: "离职", leaveDate: new Date() }
)
print(`共更新 ${techUpdate.modifiedCount} 名技术部员工`)
print("更新完成!")
运行:
mongosh update_employees.js
十三、一句话总结
“MongoDB 更新文档 =
updateOne/Many+$set/$inc+upsert+ 事务”
快速更新模板
// 单条更新
db.users.updateOne({ _id: id }, { $set: { status: "active" } })
// 批量加1
db.counters.updateMany({}, { $inc: { seq: 1 } })
// 替换文档
db.posts.replaceOne({ slug: "hello" }, newPostDoc)
官方文档:
- https://www.mongodb.com/docs/manual/reference/method/db.collection.updateOne/
- https://www.mongodb.com/docs/manual/reference/operator/update/
如需 批量导入更新、软更新(版本控制)、从 SQL UPDATE 迁移 或 实时变更流监听,欢迎继续提问!