MongoDB实战第二版笔记(8)第七章笔记
1、MongoDB更新数据库有两种实现:完整替换现有文档(update更新)或更新操作符修改文档(set操作符)。
如何抉择?替换是更通用的做法。使用文档替换时,数据从表单提交,一旦验证,就可以传递给MongoDB;不管哪个字段被更新,代码执行的更新都是相同的。目标更新(set)通常获得更好的性能,因为不需要往返服务器获取并修改文档数据。最重要的是文档更新通常很小,如果通过替换更新,每个文档平均200KB大小,则每次更新要接受和发送200KB的数据。
2、频繁使用目标更新意味着可以在序列化和传输数据上花费更少时间。
3、目标操作允许原子更新文档,使用乐观锁来实现原子更新。使用原子更新,可以使用 $inc
来原子性修改计数器,即使大并发更新,每个 $inc
都会隔离操作,要么成功要么失败。【事实上所有发送给服务器的更新都是原子性的,基于每个文档进行隔离。更新操作符被原子性调用,因为这可以让查询和更新操作在单个操作内完成。】
4、构建一个MongoDB对象的映射器来支持更新,就可通过替换实更新,这默认是合理的。绝大部分MongoDB对象映射器都使用这个策略。如果用户可以建模任意复杂的实体,然后通过替换来更新会比使用特定的更新操作符来更新简单得多。
5、乐观锁或乐观并发控制,是一种确保干净更新数据但是不需要锁定数据的数据。举例wiki,多个用户同时更新,但不希望用户更新已过时页面。使用乐观锁协议,当用户保存修改,可以包含尝试更新时间戳,如果时间戳比最新保存的版本旧,就不允许更新。如果没有用户保存任何编辑页面,则允许更新。
6、悲观锁,记录会在事务里第一次访问时被锁定,直到事务结束,在此期间,无法进行其他事务访问。
7、MongoDB的findAndModify命令【命令随环境变换,ruby是find_and_modify,核心服务器会识别findandmodify】,允许在同一个往返过程中原子更新文档并返回它。原子更新就是一个不会被其他更新中断或者与其他操作交互的操作。
如果用户在我们找到这个文档后修改之前尝试修改的文档,这个查找不会执行成功,原子更新会阻止这个情况,其他操作必须等待原子更新完成才行。
8、每个MongoDB更新都是原子性,但与findAndModify不同,它会自动返回文档。有用在于,当要获取并更新一个文档(或更新并获取它)时,可能有另外一个MongoDB用户修改这个文档,虽然更新是原子性的,但很难知道更新文档的真实状态(更新前或者后),除非使用findAndModify。
9、原子更新很重用,是因为其支持许多功能。例如,利用findAndModify构建工作队列和状态机,然后使用这些原始语句来构建事务语义,这极大地扩展了MongoDB的应用范围。
10、findAndModify命令失败会返回nil,抛出InventoryFetchFailurey异常。如果是因为网络问题失败,抛出Mongo::OPerationFailure异常。
11、MongoDB更新操作符
$inc
来增加或减少一个数值,也可以添加或减去任意数值【发生在磁盘上,只影响指定值】$set
设置某个文档特定key值,$unset
删除文档中提供的key,但是该命令对于数组却是设置数组元素的值为null而不是删除元素,要完全删除数组元素,则可以使用$pull
。rename
修改key的名字或修改子文档名字$SetOnInsert
对应目的是只想新增数组而不修改数据。
12、MongoDB数组更新操作符
$push
是数组后面追加值,默认会在数组尾部添加单独元素$pushAll
添加多个值到数组上,但是过时方法$each
和$push
组合,可以在一次更新里添加多个更新$slice
目的是方便管理经常更新的数组。当向数组添加值而不想太大,则十分有用,但必须和$push
以及$each
操作符一起使用,允许裁短数组的大小、删除旧的值。传递给$slice
的参数必须是小于或者等于0。这个参数的值是数组里允许的项目数量乘以-1。从2.6后可以传递正整数,会从数组尾部开始删除元素。$sort
帮助更新数组,因为有时候需要排序再删除$addToSet
会往数组后面添加值,但特殊在于,只会向数组里添加不存在的值【$each
只能和$addToSet
、$push
操作符一起使用】$pop
从数组中删除元素,会删除最后一个$push
的项目。$bit
在单个二进制级别来执行逻辑运算。$pull
是$pop
的复杂形势,可以通过值指定要删除的元素。$pullAll
则是同时删除多个元素。$pull
强大的特性是可以传递查询作为参数来选择要拉取的元素。
13、MongoDB允许通过原点选择器来定位要更新的元素。
14、findAndModify的参数query、update、remove需要的:
- query。查询选择器,默认为{}
- update。指定更新的文档,默认为{}
- remove。布尔值,若为true,则返回删除的对象。默认为false
- new。布尔值,若为treue,则返回修改的文档。默认为false,返回最初的文档。
- sort。指定排序方向。使用findAndModify一次酒删改一个文档,但该参数可以帮助控制哪个文档。例如,{created_at:-1}排序来处理最近创建的文档
- fields。如果只要返回部分字段,就使用该参数指定,在处理大文档很有用。
- upsert。布尔值,为true,则findAndModify作为upsert操作。如果文档不存在,则创建它。注意,如果要返回新创建的文档,则需要指定{new:true}。
15、MongoDB3.0,WiredTiger存储引擎在集合级别,提供强大的文档级别的锁。
16、更新文档的三种方式:
- 最高效。只更新文档里的单个值并且BSON文档大小不会改变时才发送。通常发生在
$inc
操作符中。$inc
只增加整数,磁盘的文档大小不会发生变化。 - 修改文档大小和数据结构。使用
$push
操作符修改文档,既增加文档的大小又修改结构。 - 重写一个文档。如果文档扩大,但不能满足现在磁盘空间,则不仅仅需要重写,还需要移动到新的空间。如果移动操作经常发生,则会非常昂贵。MongoDB会动态调整集合分配预留空间的填充因子优化该问题。意味着当一个集合中许多的需要文档迁移更新时,内部预留空间的填充因子会增加。填充因子乘以每个插入文档的大小来获取额外空间。这也许能减少未来文档重新迁移的数量。MongoDB3.0使用2的幂作为MMAPv1存储默认的记录空间分配大小。
17、操作符总结
操作符 | 作用 |
---|---|
$inc | 给定的值增加字段 |
$set | 设置字段为给定的值 |
$unset | 取消设置字段 |
$rename | 重命名字段为给定的值 |
$setOnInsert | 在upsert中,只在插入时设置字段 |
$bit | 只执行按位更新字段 |
18、数组操作符
数组操作符 | 作用 |
---|---|
$ | 根据查询选择器定位要更新的子文档 |
$push | 添加值到数组中 |
$pushAll | 添加数组到一个数组中 |
$addToSet | 添加值到数组中,重复了也不处理 |
$pop | 从数组中删除第一个或最后一个值 |
$pull | 从数组中删除匹配查询条件的值 |
$pullAll | 从数组中删除多个值 |
19、数组运算修饰符
数组操作符 | 作用 |
---|---|
$each | 与$push 和$addToSet 一起使用来操作多个值 |
$slice | 与$push 和$each 一起使用来缩小更新后的数组大小 |
$sort | 与$push 、$each 、$slice 一起来排序数组中的子文档 |
20、隔离运算符
数组操作符 | 作用 |
---|---|
$isolated | 隔离其他操作,不允许其他操作交叉更新多个文档 |