美文网首页
MongoDB 快速入门实战教程基础篇 一 :文档的 UD操作

MongoDB 快速入门实战教程基础篇 一 :文档的 UD操作

作者: you的日常 | 来源:发表于2022-01-06 09:41 被阅读0次

前一部分的文章:
MongoDB 快速入门实战教程基础篇 一 :文档的 CR操作


Update Operations

MongoDB 提供了几个方法用于更新文档,它们分别是:

db.collection.updateOne(<filter>, <update>, <options>)
db.collection.updateMany(<filter>, <update>, <options>)
db.collection.replaceOne(<filter>, <update>, <options>)

更新单个文档

updateOne() 方法会根据过滤器更新集合中的单个文档,其语法格式如下:

db.collection.updateOne(
   <filter>,
   <update>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ]
   }
)

例如将 inven 集合中名为 韦德 的球员名称改为 热火韦德,对应示例如下:

> db.inven.updateOne(
... {name: "韦德"}, 
... {$set: {name: "热火韦德"}}
... )
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

返回的结果文档包含操作状态 acknowledged,匹配的文档数 matchedCount 和修改过的文档数 modifiedCount。本次返回结果文档代表修改成功,韦德 的名字被改变了。

Upsert

在实际应用中,upsert 指令非常常见。当 upsert 的值为 true 时,如果 <filter> 并匹配到文档,那么本次操作就会将它当作新文档添加到集合中。例如当文档中没有名为 ABC 的球员时,会将 奥尼尔 添加到集合中,对应示例如下:

> db.inven.updateOne( {name: "ABC"}, {$set: {name: "奥尼尔"}}, {upsert: true})
{
    "acknowledged" : true,
    "matchedCount" : 0,
    "modifiedCount" : 0,
    "upsertedId" : ObjectId("5d15d6c718f0856b4385c123")
}

结果文档显示本次操作未匹配到文档,也未更新文档,但操作成功。相对于上一次的结果文档,本次结果文档中多出了 upsertedId,这正是 奥尼尔 文档的 _id。我们可以通过 find() 方法来验证:

> db.inven.find({name: "奥尼尔"})
{ "_id" : ObjectId("5d15d6c718f0856b4385c123"), "name" : "奥尼尔" }

果然, 奥尼尔 被添加到集合中。

更新多个文档

updateMany() 方法可以更新多个文档,其语法格式与 updateOne() 相同。假设要将球衣号大于 20 的所有球员球衣号设置为 33,对示例如下:

> db.inven.updateMany(
... {number: {$gt: 20}},
... {$set: {number: 33}}
... )
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }

其他指令如 upsert 使用时与之前相同。

update() 方法的语法格式与 updateOne() 相同,但它默认只更新单个文档。假设要将球衣号等于 33 的球员球衣号设置为 0,对应示例如下:

> db.inven.update( {number: {$eq: 33}}, {$set: {number: 0}} )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

返回文档显示只更新了 1 个文档,其他查询符合条件的文档并未被更新。如果想要更新多个文档,可以将指令 multi 设置为 true,或者使用 updateMany()

替换文档

replaceOne() 方法会根据过滤器替换集合中的单个文档,其语法如下:

db.collection.replaceOne(
   <filter>,
   <replacement>,
   {
     upsert: <boolean>,
     writeConcern: <document>,
     collation: <document>
   }
)

假设要为 奥尼尔 添加球衣号,对应示例如下:

> db.inven.replaceOne( {name: "奥尼尔"}, {name: "奥尼尔", number: 34})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

命令执行后,奥尼尔 文档从 {name: "奥尼尔"} 变成了 {name: "奥尼尔", number: 34}

Save

save() 是一个多用途的方法,它会根据 _id 是否存在而选择调用 insert() 或者 update()。当文档中存在 _id 时,save() 等效于带有 upsert 指令的 update();当文档中不包含 _id 时,save() 等效于 insert(),此时 MongoShell 将创建一个 ObjectId,并将其分配给 _idsave() 的语法格式如下:

db.collection.save(
   <document>,
   {
     writeConcern: <document>
   }
)

奥尼尔_idObjectId("5d16c699dca60c968c6d8f69"),当 save() 方法中的文档包含 _id 时会更新文档内容,对应示例如下:

> db.inven.save({_id: "5d16c699dca60c968c6d8f69", name: "奥尼尔", status: "R"})
WriteResult({
    "nMatched" : 0,
    "nUpserted" : 1,
    "nModified" : 0,
    "_id" : "5d16c699dca60c968c6d8f69"
})

{"name" : "奥尼尔" } 变成了 {"name" : "奥尼尔", "status" : "R" }。要注意的是,ObjectId("5d16c699dca60c968c6d8f69") 在命令中的写法是 "5d16c699dca60c968c6d8f69"

更新操作符

MongoDB 共有四类更新操作符,它们是:字段更新操作符、数组更新操作符、修饰操作符和按位操作符。

字段更新操作符

MongoDB 中共有 9 个字段更新操作符,它们分别是:

名称 描述
$currentDate 将字段的值设置为当前日期,可以是 DateTimestamp
$inc 将指定字段的值与传入的值相加。
$min 仅当指定的值小于现有字段值时才更新字段。
$max 仅当指定的值大于现有字段值时才更新字段。
$mul 将指定字段的值与传入的值相乘。
$rename 重命名字段。
$set 设置文档中字段的值。
$setOnInsert 如果更新导致文档插入,则设置字段的值。对修改现有文档的更新操作没有影响。
$unset 从文档中删除指定的字段。

我们将在本节中挑选几个典型的字段更新操作符进行学习,对于作用相似或语法类似的将不作赘述。例如 $min$max,我们只需要了解其中一个即可。

currentDate

$currentDate 的作用是将字段的值设为当前日期,其语法格式如下:

{ $currentDate: { <field1>: <typeSpecification1>, ... } }

其中,<typeSpecification1> 可以是一个布尔值、 {$type: "timestamp"} 或者 {$type: "date"}。在开始学习之前,我们需要准备以下数据:

> db.registers.save({_id: 1, name: "async", pwd: "123456", regTime: new Date()})

此时,regTime 的值为 ISODate("2019-07-10T08:40:02.253Z")。假设要更新 regTime的值,我们可以使用如下命令:

> db.registers.update(
... {_id: 1},
... {$currentDate:{regTime: true}
... })

命令执行后,regTime 的值就会被改变,新的文档内容类似于:

{ "_id" : 1, "name" : "async", "pwd" : "123456", "regTime" : ISODate("2019-07-10T08:43:24.981Z") }

当然,我们也可以使用 {$type: "timestamp"} 这种语法,命令如下:

> db.registers.update( 
... {_id: 1}, 
... {$currentDate:{ regTime: {$type: "timestamp"}} 
... })

命令执行后,regTime 的值也会被改变。要注意的是,由于 DateTimestamp 格式不同,所以 regTime 的值的格式将由原来的 ISODate 变成 Timestamp

inc

$inc 的作用是按指定的数量增加字段的值,其语法格式如下:

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

假设现在有一个这样的文档:

{
  _id: 1,
  sku: "abc123",
  quantity: 10,
  metrics: {
    orders: 2,
    ratings: 3.5
  }
}

如果我们需要在此基础上将 quantitymetrics.orders 的值做加法,对应示例如下:

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

命令执行后,文档将会变成下面这样:

{
   "_id" : 1,
   "sku" : "abc123",
   "quantity" : 8,
   "metrics" : {
      "orders" : 3,
      "ratings" : 3.5
   }
}

如果传入的不是数字,而是字符串或其它类型,我们将得到错误提示:

> db.products.update({sku: "abc123" },{$inc: {quantity: "async"}})
WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 14,
        "errmsg" : "Cannot increment with non-numeric argument: {quantity: \"async\"}"
    }
})

$mul 的作用是将指定字段的值与传入的值相乘,这与 $inc 类似,此处不再赘述。$mul 的语法和介绍可查阅官方文档 $mul

min

$min 的描述是“仅当指定的值小于现有字段值时才更新字段”,其语法格式如下:

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

假设有以下数据:

{ _id: 1, highScore: 800, lowScore: 200 }

最高分 highScore800,最低分 lowScore200。以下 $min 操作将用指定的 150200 进行比对,由于 150 < 200,原文档中 lowScore 的值会被更新为指定的 150。更新语句如下:

> db.scores.update( { _id: 1 }, { $min: { lowScore: 250 } } )

命令执行后,文档将会变成:

{ _id: 1, highScore: 800, lowScore: 150 }

示例中只演示了数字类型的比较,实际上 BSON 都可以进行比较,比较顺序参考 BSON comparison order$max 将指定值与现有字段值进行比较,如果指定值大于现有字段值,则更新对应字段值。这与 $min 类似,此处不再赘述。$max 的语法和介绍可查阅官方文档 $max

unset

相关文章

网友评论

      本文标题:MongoDB 快速入门实战教程基础篇 一 :文档的 UD操作

      本文链接:https://www.haomeiwen.com/subject/vryhcrtx.html