DAY7 MongoDB 资料更新(Update)

DAY7 MongoDB 资料更新(Update)

更新(update)

资料更新(Update)如同写入或删除一样,都是相同 Pattern,差别是条件比较多。

db.collection.updateOne(filter, update, options)
db.collection.updateMany(filter, update, options)

两者基本上是一样的,相信你们看完前面的 insertOne, insertMany, deleteOne, deleteMany 都有感觉了。

filter 是过虑条件,也就是你要找到欲更新文件的条件。

options 这个是更新的设定选项,在刚开始会用不到太多项目,只有一个要特别注意,就是 upsert,通常我们会设定为 true,这也是 MongoDB 很方便的地方。顾名思义,就是当欲更新的文件如果存在时,进行 update,当找不到这比文件时,就进行 insert

UpdateOne Demo - 1

马上来个范例,我们先查询,确保没有该文件,接着执行 upsert:trueupdateOne 语法:

film> db.upsert.sample.find()

film> db.upsert.sample.updateOne({},{$set:{'name':'try upsert'}},{upsert:true})
{
  acknowledged: true,
  insertedId: ObjectId("6131047cf80a26301f6a5856"),
  matchedCount: 0,
  modifiedCount: 0,
  upsertedCount: 1
}
film> db.upsert.sample.find()
[ { _id: ObjectId("6131047cf80a26301f6a5856"), name: 'try upsert' } ]
film>

可以看到 upsert.sample collection 起初是没有资料的,我使用了 find(),不带任何参数的查询,查不到任何资料。
接着再一个 updateOne 的内容里,执行後直接新增比资料,透过回传的参数也可以看到 upsertedCount 数量为 1。

  • insertedId:本次执行结果,写入的 ObjectId 清单
  • matchedCount:本次执行结果,符合查询条件的文件数量
  • modifiedCount:本次执行结果,符合查询条件且更新的文件数量
  • upsertedCount:本次执行结果,进行 upsert 的文件数量

接着将这次的 updateOne 语法来拆开来看:

db.upsert.sample.updateOne(
{},
{$set:{'name':'try upsert'}},
{upsert:true}
)

可以看到三组大括弧 {},这分别对应了上面提到的 filter, updateoptions

  • filter:这边我们直接不带条件,想进行全部文件的 update
  • update:我们设定 name 栏位的值为 try upsert,$set 是 MongoDB 的 operator 之一,这个我们之後再讲解,先忍着略过它。
  • options:这次 updateOne 中,设定值设定 upserttrue,代表找不到资料就写入。设定还有 writeConcern, collationhint 等,这个会在後面再讲解,现在提就太深入了。

UpdateOne Demo - 2

这次我们准备几笔符合查询条件的文件,使用 UpdateOne 看看会发生什麽事情。

资料库内有三笔名为 Arthas 的资料

film> db.upsert.demo2.find()
[
  { _id: ObjectId("61310798630faf5d23c909d3"), name: 'Arthas' },
  { _id: ObjectId("61310798630faf5d23c909d4"), name: 'Arthas' },
  { _id: ObjectId("61310798630faf5d23c909d5"), name: 'Arthas' },
  { _id: ObjectId("61310798630faf5d23c909d6"), name: 'Thrall' }
]

执行 updateOne,将名为 Arthas 的资料栏位改为 ErrorName

film> db.upsert.demo2.updateOne({'name':'Arthas'}, {$set:{'name':'ErrorName'}})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
film> db.upsert.demo2.find()
[
  { _id: ObjectId("61310798630faf5d23c909d3"), name: 'ErrorName' },
  { _id: ObjectId("61310798630faf5d23c909d4"), name: 'Arthas' },
  { _id: ObjectId("61310798630faf5d23c909d5"), name: 'Arthas' },
  { _id: ObjectId("61310798630faf5d23c909d6"), name: 'Thrall' }
]

可以看到执行後,再次查询,只会有第一笔被修改,因为我们执行的是 updateOne

那为什麽第一笔不是_id9d49d5 结尾的资料呢?因为 MongoDB 采用的是 natural sort,在这个情况下就是 9d3 这一笔。我们会在後面的天数讲到 natural sort,这是一个非重要的概念。

replaceOne

replaceOne,找到符合条件的文件,直接整份文件取代。

replaceOne 用法与 Update 高度相近,来看看它的长相:

db.collection.replaceOne(filter, replacement, options)

  • filter: 设定的查找文件条件
  • replacement: 新的文件内容
  • options: 设定值,与 update 的几乎一样。

我们来尝试找到一个文件,{name:'Thrall'},将它改成下面这样子

{
    'name':'NewThrall', 
    'type':'melee'
}    
film> db.upsert.demo2.find()
[
  { _id: ObjectId("61310798630faf5d23c909d3"), name: 'ErrorName' },
  { _id: ObjectId("61310798630faf5d23c909d4"), name: 'Arthas' },
  { _id: ObjectId("61310798630faf5d23c909d5"), name: 'Arthas' },
  { _id: ObjectId("61310798630faf5d23c909d6"), name: 'Thrall' }
]
film> db.upsert.demo2.replaceOne({'name':'Thrall'}, {'name':'NewThrall', 'type':'melee'})
{
  acknowledged: true,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
}
film> db.upsert.demo2.find()
[
  { _id: ObjectId("61310798630faf5d23c909d3"), name: 'ErrorName' },
  { _id: ObjectId("61310798630faf5d23c909d4"), name: 'Arthas' },
  { _id: ObjectId("61310798630faf5d23c909d5"), name: 'Arthas' },
  {
    _id: ObjectId("61310798630faf5d23c909d6"),
    name: 'NewThrall',
    type: 'melee'
  }
]

可以看到新的内容已经取代上去,特别要注意的是 _id 并没有任何异动,即便它不是客制化的 _id,仍然不会改变,因为这个操作是取代文件内容,不会影响它本身的 key。

附带一提,replaceOne 如同上面所说,设定值是几乎一样的,所以也有 upsert 功能,这边就不再示范了,结果会与 update 一样。


本系列文章会同步发表於我个人的部落格 Pie Note


<<:  Day 3 - 新人报到前的准备与莫名的焦虑感

>>:  D6 第三周 (回忆篇)

Day 25:「好慢喔,下载多少了?」- 进度条

终於到了我们的元件篇啦!!! 今天是第一个元件,所以稍微简单一点。 我们要来做下载的进度条~ 前置...

快速新增范例资料

接下来研究NoSQL的查询方式, 最好有大量范例资料使用. 可利用AWS的范例快速新增. 可先到此下...

DAY21 - 进入後端 Nestjs

还记得一开始建立专案时选择的是 Angular + Nestjs 作为专案的前後端语言吗? 什麽是 ...

第12章:SSH远端连线设定与原理介绍(三)

前言 在前一章节中,使用了ssh-keygen来演示如何使用金钥交换的方式进行验证,在本章节中,将会...

网页编排Grid-30天学会HTML+CSS,制作精美网站

Grid是什麽 Grid是砖墙式版面,使用二维的排版方式,与flexbox不同的地方是Grid一次可...