跳到主要内容

MongDB 更新

基本

语法

db.collection.update(query, update, options)
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string>, // Added in MongoDB 4.2
let: <document> // Added in MongoDB 5.0
}
)
  • query:查询条件

  • update:要更新的对象和一些更新操作符

    • 字段

      操作符语法含义
      $set{ $set: { : , ... } }用指定的值替换字段的值。
      $inc{ $inc: { : , : , ... } }将字段按指定值递增
      $unset{ $unset: { : , ... } }删除一个特定的字段。
      $rename{$rename: { : , : , ... } }更新字段的名称
      $min{ $min: { : , ... } }仅当指定值小于现有字段值时才更新该字段。如果该字段不存在,则将字段设置为指定的值。
      $currentDate{ $currentDate: { : , ... } }将字段的值设置为当前日期,可以是date,也可以是timestamp。默认类型为Date。
      $max{ $max: { : , ... } }仅当指定值大于现有字段值时才更新该字段。如果该字段不存在,则将字段设置为指定的值。
      $mul{ $mul: { : , ... } }将字段的值乘以一个数字
      $setOnInsert在upsert过程中,在创建文档时设置字段的值。 对修改现有文档的更新操作没有影响。
    • 数组

      操作符含义
      $标识数组中要更新的元素,而不显式指定元素在数组中的位置。(有时候你根本不知道元素具体位置;见案例篇)
      $[]充当占位符,为匹配查询条件的文档更新数组中的所有元素。
      $[]充当占位符,为匹配查询条件的文档更新与arrayFilters条件匹配的所有元素。
      $addToSet仅在集合中不存在元素时才将元素添加到数组中。
      $push$push可以向已有数组末尾追加元素,要是不存在就创建一个数组。
      $pop删除数组中的数据;1表示从comments数组的末尾删除一条数据,-1表示从comments数组的开头删除一条数据。
      $pull按条件删除数组中的某个元素
      $pullAll按条件删除数组中的全部元素
    • 修饰符

      操作符含义
      $each将多个值追加到数组字段;
      $position限制数组元素的数量。配合$each使用;
      $slice对数组中的元素排序。配合$each使用;
      $sort指定插入元素的位置。配合$each使用。
  • options:额外选项

    • upsert:bool,若不存在 query 的记录时,是否插入新的文档

      db.books.update(
      { item: "ZZZ135" }, // Query parameter
      { // Replacement document
      item: "ZZZ135",
      stock: 5,
      tags: [ "database" ]
      } ,
      { upsert: true } // Options
      )
    • multi:bool,是否更新所有符合查询条件的记录,默认 false

      db.books.update(
      { stock: { $lte: 10 } },
      { $set: { reorder: true } },
      { multi: true }
      )
    • writeConcern:写入安全机制,用于控制写入安全的级别。它指定了在写操作完成之前,MongoDB需要接收到的确认数。writeConcern级别越高,写操作的确认就越安全,但也会影响写的性能。

      • writeConcern有三种级别,分别是
        • 1:表示写操作需要写入主节点的内存中,但不需要确认写操作是否成功。这是默认级别。
        • majority:表示写操作需要写入大多数节点的内存中,并且需要确认写操作是否成功。
        • <number>:表示写操作需要写入指定数量的节点的内存中,并且需要确认写操作是否成功。
    • arrayFilters

      • 用于更新嵌套数组中满足指定条件的元素。它可以在更新语句中使用,以指定需要更新的嵌套数组元素的条件。

      • arrayFilters 可以包含多个条件,每个条件都是一个对象,用于指定需要更新的数组元素的查询条件。

        db.collection.update(
        { <query conditions> },
        { <update operator>: { "<array>.$[<identifier>]" : value } },
        { arrayFilters: [ { <identifier>: <condition> } ] }
        )
        // <identifier> 用来充当数组字段中与 arrayFilters 中指定的条件匹配的所有元素的占位符,必须以小写字母开头,且只能包含字母数字字符。
        db.students.insertMany( [
        { "_id" : 1, "grades" : [ 95, 92, 90 ] },
        { "_id" : 2, "grades" : [ 98, 100, 102 ] },
        { "_id" : 3, "grades" : [ 95, 110, 100 ] }
        ] )

        db.students.updateMany(
        { },
        { $set: { "grades.$[element]" : 100 } },
        { arrayFilters: [ { "element": { $gte: 100 } } ] }
        )

返回:WriteResult

  • 执行成功时
    • nMatched:匹配查询条件的文档数量
    • nUpserted:更新插入的文档数量
    • nModified:修改的文档数量
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
  • 执行失败时
    • 除了成功哪些字段之外,还包含writeConcernError
WriteResult({
"nMatched" : 1,
"nUpserted" : 0,
"nModified" : 1,
"writeConcernError": {
"code" : 64,
"errmsg" : "waiting for replication timed out",
"errInfo" : {
"wtimeout" : true,
"writeConcern" : {
"w" : "majority",
"wtimeout" : 100,
"provenance" : "getLastErrorDefaults"
}
}
})

更新操作符

字段更新操作符

$se

用来修改指定字段的值;如果指定字段不存在,则创建它。

{ $set: { <field1>: <value1>, ... } }

用例

db.products.insertOne(
{
_id: 100,
quantity: 250,
instock: true,
reorder: false,
details: { model: "14QQ", make: "Clothes Corp" },
tags: [ "apparel", "clothing" ],
ratings: [ { by: "Customer007", rating: 4 } ]
}
)

更新普通字段/嵌套字段

db.products.updateOne(
{ _id: 100 },
{ $set:
{
quantity: 500,
details: { model: "2600", make: "Fashionaires" },
tags: [ "coats", "outerwear", "clothing" ],
"details.make": "Kustom Kidz"
}
}
)

更新数组字段(按索引)

db.products.updateOne(
{ _id: 100 },
{ $set:
{
"tags.1": "rain gear",
"ratings.0.rating": 2
}
}
)

如果是要按条件更新的话,就用 arrayFilter 吧

$inc

用来增加已有键的值

{ $inc: { <field1>: <amount1>, <field2>: <amount2>, ... } }

用例

db.products.insertOne(
{
_id: 1,
sku: "abc123",
quantity: 10,
metrics: { orders: 2, ratings: 3.5 }
}
)
db.products.update(
{ sku: "abc123" },
{ $inc: { quantity: -2, "metrics.orders": 1 } }
)

$rename

用于更新字段的名称,新字段的名字不能与已有的字段名字重名;如果要修改嵌入文档名称使用 .

db.students.update({}, { $rename: { "nmae": "name" } }, { multi: true })
// or
db.students.updateMany({}, { $rename: { "nmae": "name" } })

$unset

用于删除特定字段

{ $unset: { <field1>: "", ... } }

删除 sku=unknown 中的 quantityinstock 字段

db.products.update(
{ sku: "unknown" },
{ $unset: { quantity: "", instock: "" } }
)

数组更新操作符

添加字段

$addToSet

如果元素不存在数组中则添加,如果存在则不添加;可使用 $each 修饰来添加多个元素。

{ $addToSet: { <field1>: <value1>, ... } }

用例

db.inventory.insertOne(
{ _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera" ] })

添加单个元素

db.inventory.updateOne(
{ _id: 1 },
{ $addToSet: { tags: "accessories" } }
)

$each 添加多个元素

db.inventory.updateOne(
{ _id: 2 },
{ $addToSet: { tags: { $each: [ "camera", "electronics", "accessories" ] } } }
)
$push

添加指定值到数组中,可重复。可修饰符有:

  • $each: 将多个值追加到数组字段
  • $slice: 限制数组元素的数量。配合 $each 使用
  • $sort:对数组中的元素排序。配合 $each 使用
  • $position:指定插入元素的位置。配合 $each 使用。若为空,则默认添加到末尾。
{ $push: { <field1>: <value1>, ... } }

用例

db.students.insertOne( { _id: 1, scores: [ 44, 78, 38, 80 ] } )
db.students.updateOne(
{ _id: 1 },
{ $push: { scores: 89 } }
)

添加多个值

db.students.updateOne(
{ name: "joe" },
{ $push: { scores: { $each: [ 90, 92, 85 ] } } }
)

使用多个修饰符。用例

db.students.insertOne(
{
"_id" : 5,
"quizzes" : [
{ "wk": 1, "score" : 10 },
{ "wk": 2, "score" : 8 },
{ "wk": 3, "score" : 5 },
{ "wk": 4, "score" : 6 }
]
}
)

下面的语句首先添加 { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 }quizzes 中,然后根据 score 进行降序排序,最后保留前三个元素

db.students.updateOne(
{ _id: 5 },
{
$push: {
quizzes: {
$each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ],
$sort: { score: -1 },
$slice: 3
}
}
}
)

修改字段

$

标识数组中要更新的元素,而不显式指定元素在数组中的位置。

{ "<array>.$" : value }

更新数组中的值

db.students.insertMany( [
{ "_id" : 1, "grades" : [ 85, 80, 80 ] },
{ "_id" : 2, "grades" : [ 88, 90, 92 ] },
{ "_id" : 3, "grades" : [ 85, 100, 90 ] }
] )

如果我们要更新 id=1grades 中第一个 80 为 82。此时并不知道 grades 数组中 80 的具体位置:

db.students.updateOne(
{ _id: 1,grades: 80 },
{ $set: { "grades.$" : 82 } }
)

更新数组中的文档

db.students.insert({
_id: 4,
grades: [
{ grade: 80, mean: 75, std: 8 },
{ grade: 85, mean: 90, std: 5 },
{ grade: 85, mean: 85, std: 8 }
]
})

修改该文档 gradesgrade 为 85 的 std 为 6

db.students.updateOne(
{ _id: 4, "grades.grade": 85 },
{ $set: { "grades.$.std" : 6 } }
)

使用多个数组匹配更新

db.students_deans_list.insertMany( [
{
_id: 8,
activity_ids: [ 1, 2 ],
grades: [ 90, 95 ],
deans_list: [ 2021, 2020 ]
}
] )

前几个字段用于查询条件查询,deans_list 作为 $set 占位符使用

db.students_deans_list.updateOne(
{ activity_ids: 1, grades: 95, deans_list: 2021 },
{ $set: { "deans_list.$": 2022 } }
)
$[]
{ <update operator>: { "<array>.$[]" : value } }

用例

db.students.insertMany( [
{ "_id" : 1, "grades" : [ 85, 80, 80 ] },
{ "_id" : 2, "grades" : [ 88, 90, 92 ] },
{ "_id" : 3, "grades" : [ 85, 100, 90 ] }
] )

下面将所有数组 grades 增加 10

db.students.updateMany(
{ },
{ $inc: { "grades.$[]": 10 } },
)
$[<identifier>]

给数组筛选提供个过滤器,配合 option 中的 arrayFilters 使用,如果是嵌套文档还是使用 .

db.students.insertMany( [
{ "_id" : 1, "grades" : [ 95, 92, 90 ] },
{ "_id" : 2, "grades" : [ 98, 100, 102 ] },
{ "_id" : 3, "grades" : [ 95, 110, 100 ] }
] )

更新所有grades数组大于等于100的记录,将其设置为100

db.students.updateMany(
{ },
{ $set: { "grades.$[element]" : 100 } },
{ arrayFilters: [ { "element": { $gte: 100 } } ] }
)

删除字段

$pop

删除数组中第一个或者最后一个元素;-1 删除第一个元素,1 表示删除最后一个元素

{ $pop: { <field>: <-1 | 1>, ... } }

例子

db.students.insertOne( { _id: 1, scores: [ 8, 9, 10 ] } )

以下语句删除students中scores中第一个元素

db.students.updateOne( { _id: 1 }, { $pop: { scores: -1 } } )

$pull 条件匹配删除值

从现有数组中删除一个或多个与指定条件匹配的值的所有实例。

{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }

用例

db.stores.insertMany( [
{
_id: 1,
fruits: [ "apples", "pears", "oranges", "grapes", "bananas" ],
vegetables: [ "carrots", "celery", "squash", "carrots" ]
},
{
_id: 2,
fruits: [ "plums", "kiwis", "oranges", "bananas", "apples" ],
vegetables: [ "broccoli", "zucchini", "carrots", "onions" ]
}
] )

下面的操作将移除:

  • 所有文档 fruits 数组中 "apples""oranges"
  • 所有文档 vegetables 数组中 "carrots"
db.stores.updateMany(
{ },
{ $pull: { fruits: { $in: [ "apples", "oranges" ] }, vegetables: "carrots" } }
)

删除所有匹配指定 $pull 条件的项

db.profiles.insertOne( { _id: 1, votes: [ 3, 5, 6, 7, 7, 8 ] } )

删除所有 votes 大于等于6的元素

db.profiles.updateOne( { _id: 1 }, { $pull: { votes: { $gte: 6 } } } )
$pullAll 精确匹配删除所有值

从数组中删除所有指定值;只能精确匹配,无法条件匹配

{ $pullAll: { <field1>: [ <value1>, <value2> ... ], ... } }

用例

db.survey.insertOne( { _id: 1, scores: [ 0, 2, 5, 5, 1, 0 ] } )

下面的例子将删除scores中所有0,5的元素

db.survey.updateOne( { _id: 1 }, { $pullAll: { scores: [ 0, 5 ] } } )

等价于:

db.survey.updateOne( { _id: 1 }, { $pull: { scores: {$in:[ 0, 5 ]} } } )