MongoDB文档操作

一、插入并保存文档

1.1 insert()方法

1.2 save()方法

1.3 批量插入

1.4 插入原理与方法

二、删除文档

2.1 remove()方法

2.2 deleteOne()以及deleteMany()

2.3 drop()

三、文档更新

3.1 原子性

3.2 update()方法

3.3 文档替换

3.4 修改器

3.4.1 $set

3.4.2 $inc

3.5 数组修改器

3.6 数组作为数据集

3.7 删除数组元素

3.8 基于位置的数组修改器

3.8.1 通过位置

3.8.2 定位操作符

3.9 修改器速度

3.10 多个文档的更新

参考文献

 

 

一、插入并保存文档

1.1 insert()方法

    db.COLLECTION_NAME.insert(document)

    insert()方法是向文档中插入数据最基本的方法,该方法参数接受一个文档,将文档加入到目标集合中。

    如将文档{name:"xxx",age:25}插入集合foo中,只需要如下操作:

        db.foo.insert({name:"xxx",age:25})

    就可在集合中插入该文档。

    需要注意的是,因为我们插入的文档中没有"_id"键,所以这个操作会给文档增加一个自动生成的"_id"键,然后再将其保存在数据库中。这个键并不是地址,也不是简单递增的,而是通过"时间戳+机器编号+进程编号+序列号"生成,所以每个"_id"都是唯一的。如下图所示"_id"为:5bbd4dd38f06ac759d5e8a00,就可分解为时间戳(前四字节):5bbd4dd3 + 机器号(三字节):8f06ac + 进程编号(两字节):759d + 序列号(三字节):5e8a00 。

MongoDB文档操作

 

1.2 save()方法

    save()是一个shell函数,它不仅仅支持插入操作,还支持更新操作,它只有一个参数:文档,说的更详细些的话,则是该文档的"_id"键的值,如果已有一个文档具有相同的"_id"键值,则执行更新操作,具体则是调用upsert()函数,否则则调用insert()执行更新操作。

  1. db.collection.save(  
  2.    <document>,  
  3.    {  
  4.      writeConcern: <document>  
  5.    }  
  6. )  

 

1.3 批量插入

    除了insert()方法外,还可使用batchInsert()方法实现批量插入,该函数与insert()方法不同的地方在于,它接受一个文档数组作为参数。    

例子:在集合foo中插入{name:"aaa",age:20}, {name:"bbb",age:25}, {name:"ccc",age:30}三条文档:

  1. db.foo.batchInsert([{name:"aaa",age:20}, {name:"bbb",age:25}, {name:"ccc",age:30}])  

 

1.4 插入原理与方法

    当执行数据插入的时候,驱动程序会把数据转化成BSON格式,然后将数据导入数据库。数据库会解析BSON,并对其进行最基本的检查:检查文档的基本结构。如文档大小(应小于16MB),"_id"字段等。因此非法数据是无法被甄别的,所以需要对数据源的数据进行判断,或者在数据插入数据库之前做数据校验。

 

二、删除文档

2.1 remove()方法

  1. db.collection.remove(  
  2.    <query>,  
  3.    <justOne>  
  4. )  

    MongoDB v2.6版本对remove()函数进行了更新,修改了参数。

  5. db.collection.remove(  
  6.    <query>,  
  7.    {  
  8.      justOne: <boolean>,  
  9.      writeConcern: <document>  
  10.    }  
  11. )  

    该函数的所有参数都为可选参数,如果全为空,则代表删除集合里的所有文档。

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 1,则只删除一个文档。
  • writeConcern :(可选)抛出异常的级别。

     

2.2 deleteOne()以及deleteMany()

    deleteOne()以及deleteMany()可以认为是remove()方法的拆解,deleteOne()删除满足条件的一个文档,deleteMany()删除满足条件的所有文档

  1. db.collection.deleteOne(  
  2.    <filter>,  
  3.    {  
  4.       writeConcern: <document>,  
  5.       collation: <document>  
  6.    }  
  7. )  
  8.     
  9. db.collection.deleteMany(  
  10.    <filter>,  
  11.    {  
  12.       writeConcern: <document>,  
  13.       collation: <document>  
  14.    }  
  15. )  

 

2.3 drop()

    drop()方法并不对文档进行操作,而是直接删除集合,该函数适用于上文remove()无参数的情况,该函数直接删除集合比删除所有的文档效率更高。

  1. db.collection.drop( { writeConcern: <document> } )  

 

三、文档更新

3.1 原子性

    在MongoDB中,更新单个的文档操作是原子性的。默认情况下,如果一个update()更新多个文档,那么对每个文档的更新是原子性的,但是对整个update而言则不是原子性的。有可能存在前一个文档更新成功,后面的文档更新失败的情况。由于单个文档的更新是原子性的,如果两个更新同时发生,就会出现阻塞,先到的先执行,所以文档最终结果由靠后的操作决定。

 

3.2 update()方法

  1. db.collection.update(  
  2.    <query>,  
  3.    <update>,  
  4.    {  
  5.      upsert: <boolean>,  
  6.      multi: <boolean>,  
  7.      writeConcern: <document>,  
  8.      collation: <document>,  
  9.      arrayFilters: [ <filterdocument1>, ... ]  
  10.    }  
  11. )  

update()方法有两个参数,一个是查询文档,用于定位需要更新的目标文档;另一个是修改器,用于说明要对找到的文档进行哪些修改。

 

3.3 文档替换

    替换操作是用一个新的文档替换旧的文档,这一般用于修改比较大的情况。该操作需要一个中间变量来存储新值,最后再将旧值覆盖。

    下图使用该操作完成了文档值的更新操作:将"xi"的信息替换为"xixi",当然,这存在着更好的方法。

MongoDB文档操作

MongoDB文档操作

    另外,使用update()更新时最好指定一个唯一的键,如"_id",以防匹配到相同的字段导致跟新失败。

3.4 修改器

3.4.1 $set

    "$set"可以完成特定字符的修改,如用来指定一个字段的值。如果该字段不存在,则创建它。

    下图对"name":"ahn"文档中的"status"值进行修改,将原来的"A"改为"D"。

MongoDB文档操作

    "$set"还可用来修改键的类型以及内嵌文档,使用"$unset"还可将键删除。

3.4.2 $inc

    "$inc"可以对数据进行增加或减少,这个操作只针对数字类型,如整形、长整形与双精度浮点型。如果操作的该键不存在,则创建一个。

    如将info集合中name: "wangsan"文档对应的age减2:

MongoDB文档操作

 

3.5 数组修改器

    "$push"将数据插入数组末尾,如果没有该数组,则创建一个。

    如在info集合中数组元素的追加,对name为'bob'的文档添加一个数组元素。

MongoDB文档操作

    "each""$push"配合使用,可以一次性push多个值。

  1. db.info.update({ "name" : "bob"},{$push: {"detail": {$each: [{"city" : "Beijing"},{ "city" : "Shanghai"}]}}})  

    上诉操作可在"detail" 中插入两个值。

    "$slice"+"$push"可规定数组长度,"$slice"的值必须为负整数。

    "$sort"则可根据某字段的值对所有对象进行排序。

 

3.6 数组作为数据集

    "$addToSet"向数组中添加元素,如果元素已经存在就不添加。

    "$addToSet"+"$set":添加多个不重复的值。

 

3.7 删除数组元素

    "$pop"将数组看成队列,每次pop都删除一个元素。{"$pop":{"key":1}}从数组末尾删除一个元素,"key":-1则从头部删除一个元素。

    "$pull"可根据条件来删除元素。如db.foo.update({},{"$pull":{"class":"English"}})可将class数组中的"English"元素删除。

 

3.8 基于位置的数组修改器

3.8.1 通过位置

    数组下标可直接作为键来选择元素,且以0开头。

    如过我们要将上图文档中detail数组里第一个元素的"class"元素改为"0701",则可用下面的方法:

  1. db.info.update({ "name" : "bob"},{$set: {"detail.0.class":"0701"}})  

 

3.8.2 定位操作符

    但很多时候,我们并不知道需要修改的数组的下标,所以我们就需要使用定位操作符"$",用来定位查询文档已经匹配的数组元素,并进行更新。

    如上面的修改"class",使用定位符如下所示:

MongoDB文档操作

    另外,定位符只更新匹配到的第一个元素。

 

3.9 修改器速度

    最初将文档插入到MongoDB时,一次插入的文档在磁盘上的位置是相邻的,且文档之间没有多余的空间。因此当一个文档变大时,原有的位置就无法放下该文档了,所以这个文档就会被移动位置。

    文档创建之初:(该示例源于《MongoDB权威指南》p.43)

MongoDB文档操作

    当对中间的文档的数据进行增加时,这个文档就会被移动到文档尾部:

MongoDB文档操作

    当MongoDB不得不移动文档时,它会修改集合的填充因子——为每个新文档预留的增长空间。初始化时,填充因子为1,即完全没有多余的空间。在执行完上面的操作后,填充因子扩大为1.5,即每个新加入的文档在之后预留自身1/2大小的空间。如果文档更新操作频繁,移动次数多,填充因子就会增大。反之,不再有文档移动,填充因子就会缓慢减小。

MongoDB文档操作

 

    这也是有时push成为系统瓶颈的原因,文档更新造成文档磁盘结构的变化,导致大量的硬盘读写操作。

 

3.10 多个文档的更新

    默认的update操作只会更新第一个匹配,要对数据进行批量更新,则需要使用update的第四个参数,将其设为true,表示是否更新全部查到的文档。而有第四个就需要第三个,第三个参数也接收bool类型,表示是否要将我们更新的文档作文新文档插入,默认为false。

    例子:将info集合中将所有status为"B"对应的文档值的status全部改成"B+":

MongoDB文档操作

 

 

 

参考文献:

《MongoDB权威指南》 人民邮电出版社

《NoSQL数据库原理与应用》 学校编著

    MongoDB官方文档

上一篇:前程无忧爬虫源码及分析(一)


下一篇:从有值的ID到汉字编码