MongoDB的更新操作
文章目录
示例集合
|
|
更新集合中的文档
为了更新文档,MongoDB提供了更新操作符,例如$set修改字段值。
$set如果该字段不存在,则某些更新运算符(例如)将创建该字段。
注意
从MongoDB 4.2开始,MongoDB可以接受聚合管道来指定要进行的修改而不是更新文档。
更新单个文件
以下示例在集合上使用 Collection.UpdateOne方法,更新item等于"paper"的第一个文档 :
|
|
更新操作:
- 使用
$set
操作员更新的值 size.uom字段为"cm"和status字段为"P", - 使用
$currentDate
运算符将lastModified字段的值更新为当前日期。如果lastModified字段不存在,$currentDate
将创建该字段。
更新多个文件
以下示例在集合上使用 Collection.UpdateMany方法来更新qty小于50的所有文档:
|
|
更新操作:
- 使用
$set
操作员更新的值 size.uom字段为"cm"和status字段为"P", - 使用
$currentDate
运算符将lastModified字段的值更新为当前日期。如果lastModified字段不存在,$currentDate
将创建该字段。
更换文件
要替换除_id 字段以外的文档的所有内容,请将一个全新的文档作为第二个参数传递给 Collection.ReplaceOne。
替换文档时,替换文档必须仅由字段/值对组成;即不包括更新运算符表达式。
替换文档可以具有与原始文档不同的字段。在替换文档中,_id由于该_id字段是不可变的,因此可以省略该字段;但是,如果您包含该_id字段,则该字段必须与当前值具有相同的值。
下面的示例替换集合中的第一个item: "paper"
的文档:
|
|
特性
原子性
MongoDB中的所有写操作都是单个文档级别的原子操作。
_id字段
设置后,您将无法更新该_id字段的值,也无法将现有文档替换为具有不同_id字段值的替换文档。
字段顺序
除以下情况外,MongoDB在写操作后保留文档字段的顺序:
- 该_id字段始终是文档中的第一个字段。
- 包含renaming字段名称的更新可能会导致文档中字段的重新排序。
增补选项
当您指定选项upsert为true时:
- 如果文档符合查询条件,请 db.collection.update()执行更新。
- 如果没有文件的查询条件匹配, db.collection.update()插入一个单一的文件。
如果在分片集合上指定,则必须在中包含完整的分片密钥。
警告:为避免多次插入同一文档,请仅在字段被唯一索引时使用。
给定一个名为集合people在没有文档有name保存的价值领域Andy,考虑当多个客户端在同一时间发出以下db.collection.update()与upsert: true:
|
|
如果所有db.collection.update()操作query在任何客户端成功插入数据之前完成了该部分,并且该name字段上没有唯一索引,则每个更新操作都可能导致插入。
为防止MongoDB多次插入同一文档,请在字段上创建唯一索引name。使用唯一索引,如果多个应用程序使用发出相同的更新,则恰好一个将成功插入一个新文档。
其余操作将是:
- 更新新插入的文档,或者
- 当他们尝试插入重复项时失败。如果操作由于重复的索引键错误而失败,则应用程序可以重试该操作,该操作将作为更新操作成功。
写确认
对于写入问题,您可以指定MongoDB向写入操作请求的确认级别。
聚合管道更新
从MongoDB 4.2开始,您可以将聚合管道用于更新操作。通过更新操作,聚合管道可以包括以下阶段:
- $addFields
- $set
- $project
- $unset
- $replaceRoot
- $replaceWith
使用聚合管道可以实现更具表达力的更新语句,例如根据当前字段值表达条件更新,或使用另一个字段的值更新一个字段。
示例1
创建一个示例students集合(如果该集合当前不存在,则插入操作将创建该集合):
|
|
以下db.collection.updateOne()操作使用聚合管道通过以下方式更新文档:_id: 3
|
|
具体来说,管道包含一个$set
阶段,该阶段将添加test3:98到文档中(并将其值设置为),并将modified字段设置为当前日期时间。对于当前日期时间,该操作将聚合变量NOW用于(访问变量,在变量前加前缀$$
并用引号引起来)。
示例2
创建一个示例students2集合(如果该集合当前不存在,则插入操作将创建该集合):
|
|
以下 db.collection.updateMany()操作使用聚合管道来标准化文档的字段(即,集合中的文档应具有相同的字段)并更新该 modified字段:
|
|
具体来说,管道包括:
- 一个$replaceRoot与$mergeObjects表达为设置默认值quiz1,quiz2,test1和test2字段。聚合变量ROOT是指正在修改的当前文档(以访问该变量,使用前缀 $$和引号引起来)。当前文档字段将覆盖默认值。
- 一个
$set
阶段到更新modified领域的当前日期时间。对于当前日期时间,该操作将聚合变量NOW用于(访问变量,在变量前加前缀$$并用引号引起来)。
示例3
创建一个示例students3集合(如果该集合当前不存在,则插入操作将创建该集合):
|
|
以下db.collection.updateMany()操作使用聚合管道以计算的平均成绩和字母成绩更新文档。
|
|
具体来说,管道包括:
- $set阶段,用于计算tests数组元素的截断平均值并将modified 字段更新为当前日期时间。要计算平均值,阶段使用$avg和$trunc 表达式。对于当前日期时间,该操作将聚合变量NOW用于(访问变量,使用前缀$$并用引号引起来)
- 基于使用表达式$set添加grade字段
示例4
创建一个示例students4集合(如果该集合当前不存在,则插入操作将创建该集合):
|
|
以下db.collection.updateOne()操作使用聚合管道通过以下方式向文档_id: 2
添加测验分数:
|
|
示例5
创建一个temperatures包含摄氏温度的示例集合(如果该集合当前不存在,则插入操作将创建该集合):
|
|
以下db.collection.updateMany()操作使用聚合管道以华氏度的相应温度更新文档:
|
|
具体来说,管道包括一个$addFields 阶段,以添加一个新的数组字段tempsF,该字段包含华氏温度。要将tempsC数组中的每个摄氏温度转换为华氏温度,该阶段使用 $map带有$add和的 $multiply表达式。
文章作者 Forz
上次更新 2020-05-11