MongoDB 常用的更新修饰符(Update Modifiers)有哪些?
MongoDB 的更新修饰符(Update Modifiers/Operators)是用于在 update、updateOne、updateMany 或 findOneAndUpdate 等操作中修改文档内容的特殊关键字。它们以 $ 符号开头。
为了方便记忆和查阅,我将它们分为 字段类、数组类 和 修饰类 三大类。
一、 字段更新操作符 (Field Update Operators)
这些操作符用于修改文档中某个具体字段的值。
| 操作符 | 描述 | 示例 |
|---|---|---|
$set |
最常用。设置字段的值。如果字段不存在,则创建该字段。 | { $set: { status: "active", age: 25 } } |
$unset |
删除指定的字段。值通常设为 "" 或 1(值不重要)。 |
{ $unset: { temporary_field: "" } } |
$inc |
对数值字段进行增减(原子操作)。传入负数即为减。 | { $inc: { views: 1, balance: -100 } } |
$mul |
将字段的值乘以指定的数值。 | { $mul: { price: 1.1 } } (涨价 10%) |
$rename |
重命名字段名称。 | { $rename: { "oldName": "newName" } } |
$min |
仅当指定值小于当前字段值时才更新(保留最小值)。 | { $min: { best_score: 98 } } |
$max |
仅当指定值大于当前字段值时才更新(保留最大值)。 | { $max: { high_score: 500 } } |
$currentDate |
将字段值设置为当前日期/时间(Date 或 Timestamp 类型)。 | { $currentDate: { lastModified: true } } |
$setOnInsert |
配合 upsert: true 使用。仅在插入新文档时设置字段,如果是更新旧文档则不执行。 |
{ $setOnInsert: { createdAt: new Date() } } |
二、 数组更新操作符 (Array Update Operators)
这些操作符专门用于处理数组类型的字段。
| 操作符 | 描述 | 示例 |
|---|---|---|
$push |
向数组末尾添加一个元素。 | { $push: { tags: "mongodb" } } |
$addToSet |
向数组添加元素,但只有当该元素不存在时才添加(保证数组唯一性)。 | { $addToSet: { tags: "database" } } |
$pop |
删除数组中的第一个或最后一个元素。1: 删除最后一个;-1: 删除第一个。 |
{ $pop: { items: 1 } } |
$pull |
删除数组中匹配特定条件的所有元素。 | { $pull: { tags: "outdated" } } { $pull: { users: { age: { $lt: 18 } } } } |
$pullAll |
删除数组中包含在指定列表中的所有值(完全匹配)。 | { $pullAll: { scores: [0, 5] } } |
三、 $push 的修饰符 (Modifiers for $push)
在使用 $push 时,可以配合以下修饰符来控制插入行为(例如一次插入多个、排序、限制长度)。
| 修饰符 | 描述 | 示例 |
|---|---|---|
$each |
配合 $push 或 $addToSet 使用,一次添加多个值。 |
{ $push: { scores: { $each: [90, 85, 99] } } } |
$slice |
配合 $push 使用,限制数组的最大长度。0 清空,负数保留最后 N 个。 |
{ $push: { logs: { $each: [newLog], $slice: -5 } } } (只保留最后5条) |
$sort |
配合 $push 使用,在插入后对数组进行排序。 |
{ $push: { scores: { $each: [70], $sort: -1 } } } (插入后降序排列) |
$position |
配合 $push 使用,指定插入的位置(索引)。 |
{ $push: { list: { $each: ["top"], $position: 0 } } } (插到头部) |
四、 数组占位符 (Array Positional Operators)
当你不知道数组元素的具体索引,但想更新匹配查询条件的那个元素时使用。
| 占位符 | 描述 | 示例 |
|---|---|---|
$ |
更新第一个匹配查询条件的数组元素。 | db.coll.updateOne({ "grades.grade": 80 }, { $set: { "grades.$.std": 2 } }) |
$[] |
更新数组中的所有元素。 | { $inc: { "grades.$[].score": 10 } } (所有成绩加10分) |
$[<identifier>] |
配合 arrayFilters 选项,更新满足特定条件的元素。 |
update(..., { $set: { "grades.$[elem].score": 100 } }, { arrayFilters: [ { "elem.score": { $gte: 90 } } ] }) |
常见场景举例
1. 用户点赞(计数器 +1):
javascript
db.posts.updateOne(
{ _id: 123 },
{ $inc: { likes: 1 } }
);
2. 修改用户信息(如果不存在则创建,记录创建时间):
javascript
db.users.updateOne(
{ _id: 1 },
{
$set: { name: "Alice", lastLogin: new Date() },
$setOnInsert: { createdAt: new Date() } // 只有是新插入时才写入 createdAt
},
{ upsert: true }
);
3. 给文章添加标签(不重复添加):
javascript
db.articles.updateOne(
{ _id: 123 },
{ $addToSet: { tags: "tech" } }
);
4. 维护一个固定长度的日志数组(只保留最近 100 条):
javascript
db.logs.updateOne(
{ _id: 1 },
{
$push: {
history: {
$each: ["New Log Entry"],
$slice: -100 // 负数表示保留最后 100 个
}
}
}
);