Skip to content

MongoDB - 更新文档

本教程涵盖了在 MongoDB 中修改文档的现代方法:updateOne()、updateMany() 和 replaceOne()。我们还将讨论强大的更新操作符(update operators)和 ‘upsert’ 选项。旧的 update() 和 save() 方法现已弃用。

要修改文档中的字段,您必须使用更新操作符。这些是带有 $ 前缀的特殊关键字,定义了如何更改数据。

  • $set: 设置字段的值。如果字段不存在,则会创建它。
  • $inc: 将数字字段的值递增指定量。
  • $unset: 从文档中移除指定字段。
  • $push: 向数组中添加元素。
  • $pull: 从数组中移除值的所有实例。

此方法更新单个匹配指定过滤器的文档。即使有多个文档匹配,也只会更新找到的第一个文档。

db.COLLECTION_NAME.updateOne(
<filter>,
<update>,
<options>
);

让我们更新 users 集合中的用户资料。

// 初始文档:
// { _id: 1, name: "Alice", status: "active", logins: 5 }
db.users.updateOne(
{ name: "Alice" }, // 过滤器
{ // 更新
$set: { status: "active_pro" },
$inc: { logins: 1 }
}
);
// 结果:
// { "acknowledged": true, "matchedCount": 1, "modifiedCount": 1 }

此方法更新所有匹配过滤器的文档。

假设我们需要存档 2020 年之前发布的所有博客文章。

db.posts.updateMany(
{ year: { $lt: 2020 } }, // 过滤器:年份小于 2020 的文章
{ $set: { status: "archived" } } // 更新
);
// 结果(如果更新了 50 篇文章):
// { "acknowledged": true, "matchedCount": 50, "modifiedCount": 50 }

此方法用新文档替换单个文档的整个内容,但不可变的 _id 字段除外。**注意:**此方法不接受更新操作符($set、$inc 等)。

// 原始文档: { _id: 1, name: "Alice", status: "active" }
db.users.replaceOne(
{ name: "Alice" },
{ name: "Alice Smith", status: "inactive", reason: "Migrated to new system" }
);
// 新文档: { _id: 1, name: "Alice Smith", status: "inactive", ... }

所有更新方法都接受 upsert 选项。当设置为 true 时,如果没有文档匹配过滤器,则会根据过滤器和更新表达式创建一个新文档。这对于“更新或插入”逻辑非常有用。

// 尝试更新 'user456' 的设置。如果不存在,则创建它们。
db.userSettings.updateOne(
{ userId: "user456" },
{ $set: { theme: "dark", notifications: true } },
{ upsert: true }
);

如原子操作章节所述,findOneAndUpdate() 是一种特殊用途的方法,它在同一操作中更新单个文档并返回它。默认情况下,它返回更新 前 的文档。您可以设置选项 { returnNewDocument: true } 来获取更新 后 的文档。

update() 方法已弃用。它的行为令人困惑,因为它默认只更新一个文档,需要 { multi: true } 才能更新多个。现在这已明确分离为 updateOne() 和 updateMany()。

save() 方法也已弃用。它是一个包装器,如果存在 _id 则更新文档,如果不存在则插入文档。此功能现在由 replaceOne()、updateOne() 或使用 upsert: true 选项更好地、更明确地处理。