updateOne、updateMany 与 replaceOne
本教程共 50 篇 · 第 23 篇 · 更新于 2026-07-30 · 约 7 分钟阅读
23. updateOne、updateMany 与 replaceOne
本节目标:分清三个更新方法的区别,知道 updateOne 只动第一条、updateMany 动全部,replaceOne 会整篇替换,并掌握 upsert 的「有则改、无则插」。
上一章讲了更新运算符,这一章讲「用什么方法把更新发出去」。三个方法签名很像,差别在「影响几条」和「怎么改」。
db.products.insertMany([
{ _id: 101, name: "机械键盘", price: 399, stock: 50, category: "外设" },
{ _id: 102, name: "无线鼠标", price: 129, stock: 120, category: "外设" },
{ _id: 103, name: "27寸显示器", price: 1099, stock: 30, category: "显示器" }
])
updateOne:只改第一条
db.collection.updateOne(筛选, 更新) 只更新第一个匹配到的文档,其余不管:
// 给第一个「外设」类商品降价 20
db.products.updateOne(
{ category: "外设" },
{ $set: { price: 100 } }
)
返回结果里 matchedCount 是 1、modifiedCount 是 1。哪怕有 100 个外设,也只有 1 个被改。
Warning忘写运算符、直接传
{ price: 100 }给 updateOne,会用这篇文档替换掉原文档,其他字段全没。更新一定要用运算符包起来。
updateMany:改所有匹配
把 updateOne 换成 updateMany,所有匹配文档都被更新:
// 所有「外设」类商品库存统一加 10
db.products.updateMany(
{ category: "外设" },
{ $inc: { stock: 10 } }
)
返回里 modifiedCount 会是 2(机械键盘和无线鼠标都改了)。
两个方法怎么选
| 方法 | 影响范围 | 适合场景 |
|---|---|---|
updateOne | 仅第一条 | 按唯一键改一条,如 _id |
updateMany | 全部匹配 | 批量改一类数据 |
Tip用
_id当筛选条件时,用updateOne就够了,因为_id本来就唯一。
upsert:没有就插入
给方法加第三个参数 { upsert: true },意思是「匹配不到就按筛选条件插入一篇新文档」:
// 若没有 _id 为 104 的商品,就新建它
db.products.updateOne(
{ _id: 104, name: "USB-C hub" },
{ $set: { price: 199, stock: 80, category: "外设" } },
{ upsert: true }
)
返回的 upsertedId 会带上新插入的 _id。如果本来就存在,就走正常更新。
Noteupsert 时,筛选条件里的等值字段(如
_id、name)会成为新文档的初始字段,再叠加$set里的内容。
replaceOne:整文档替换
replaceOne 不用运算符,而是用一篇完整新文档替换旧文档(除了 _id 不动):
// 用全新文档替换 _id 为 103 的商品
db.products.replaceOne(
{ _id: 103 },
{ name: "27寸显示器Pro", price: 1299, stock: 25, category: "显示器" }
)
注意:category 等字段会被保留或按新文档来,_id: 103 不变,但原文档里没在新文档出现的字段(如 tags)会消失。
Warning
replaceOne是「整篇覆盖」,会丢掉旧文档里没写进新文档的字段。大多数场景用updateOne+$set更安全,replaceOne 只在你想彻底重写一篇时才用。
完整方法对比
| 方法 | 更新几条 | 更新方式 | 典型用途 |
|---|---|---|---|
updateOne | 第一条 | 运算符局部改 | 改单条已知记录 |
updateMany | 全部 | 运算符局部改 | 批量改一类 |
replaceOne | 第一条 | 整篇替换 | 彻底重写单条 |
学完更新方法,下章我们看数组专属的更新运算符,比如往购物车里加商品。