MongoDB权威指南学习笔记03

本文涉及的产品
云数据库 MongoDB,通用型 2核4GB
简介:

章节:第三章 创建、更新及删除文档

时间:2013-07-22

内容:

  1. 插入并保存文档

    1. 使用insert方法:如

      1
      db.foo.insert({ "bar"  "baz" })
    2. 批量插入

      1. 批量插入能传递一个由文档构成的数组给数据库,且一次批量插入只是单个的TCP请求,无需处理大量的消息头,避免了许多零碎的请求所带来的开销

      2. 只有插入多个文档到一个集合时,才能提高效率,而不能用批量插入一次对多个集合执行操作

      3. 要是只导入原始数据,可以使用命令行工具,如mongoimport,而不是批量插入

    3. 插入:原理和作用

      1. 当执行插入时,使用的驱动程序会将数据转换成BSON形式,然后将其送入数据库

      2. 数据库解析BSON,检验是否包含“_id”键并且文档不超过4MB

      3. MongoDB在插入时不做别的数据校验,也不执行代码,所以也就没有注入式攻击的可能,但副作用是允许插入无效的数据

  2. 删除文档

    1. 删除特定文档,如

      1
      db.mailing. list .remove({ "opt-out"  : true})
    2. 删除集合中的所有文档,如db.users.remove(),但不会删除集合本身,原有的索引也会保留

    3. 删除速度:通常删除文档会很快,但若要清楚整个集合的文档,则直接删除集合(然后重建索引)会更快,如db.drop_collection("bar")即是删除集合bar

  3. 更新文档

    1. 更新文档的方法update有2个参数,一个是查询文档,用来找出要更新的文档,另一个是修改器文档,描述对找到的文档做哪些更改

    2. 更新操作是原子的,若是两个更新同时发生,先到达服务器的先执行,接着执行另外一个

    3. 文档替换:

      1. 更新最简单地情形就是完全用一个新文档替代匹配的文档,这适用于模式结构发生了较大变化时,如

        1
        db.users.update({ "name"  "joe" } , joe)
      2. 常见错误就是查询条件匹配了多个文档,然后更新的时候由于第二次参数的存在就产生重复的“_id”值,数据库会报错,不做任何修改

    4. 使用修改器

      1. 通常文档只会有一部分要更新,利用原子的更新修改器,可以使得这种部分更新极为高效

      2. 更新修改器是种特殊的键,用来指定复杂的更新操作,比如调整、增加或者删除键,还可以操作数组或者内嵌文档

      3. 使用修改器时,"_id"的值不能改变(而整个文档替换时是可以改变的);其他键值,包括其他唯一索引的键,都是可以更改的

      4. "$set"修改器:“$set”用来指定一个键的值,若键不存在,则创建它,如

        1
        db.users.update({ "name" : "joe" },...{ "$set" :{ "favorite book" : "green eggs and ham" }})

        也可以用“$unset”将键完全删除,如

        1
        db.users.update({ "name" : "joe" },{ "$unset" :{ "favorite book" : 1 }})
      5. "$inc"修改器:“$inc”修改器用来增加已有键的值,或者在键不存在时创建一个键,如

        1
        db.games.update({ "game" : "pinball" , "user" : "joe" },...{ "$inc" :{ "score" : 50 }})

        “$inc”只能用于整数、长整数或双精度浮点数,用在其它类型的数据上会导致操作失败;另外“$inc”键的值必须为数字,不能使用字符串、数组或其他非数字的值

      6. 数组修改器:用在值为数组的键上,如果指定的键已存在,"$push"会向已有的数组末尾加入一个元素,要是没有就会创建一个新的数组,如

        1
        db.blog.posts.update({ "title" : "A blog post" },{$push:{ "comments" :...{ "name" : "joe" , "email" : "joe@example.com" , "content" : "nice post." }}})

        如果一个值不在数组中再将其加进去,可以用“$ne”或“$addToSet”实现,如

        1
        2
        3
        db.papers.update({ "authors cited" :{ "$ne" : "Richie" }},...{ "$push" :{ "authors cited" : "Richie" }})
        db.users.update({ "_id" :ObjectId( "4b2d75476cc6113d5ee930164" )},...{ "$addToSet" :{ "emails" : "joe@gmail.com" }})

        将“$addToSet”和“$each”组合起来,可以添加多个不同的值,而用“$ne”和“$push”组合就不能实现,如

        1
        db.users.update({ "_id" :ObjectId( "4b2d75476cc6113d5ee930164" },{ "$addToSet" :...{ "emails" :{ "$each" :[ "joe@php.net" , "joe@example.com" , "joe@python.org" ]}}})

        若是把数组看成队列或栈,可以用“$pop”,此修改器可以从数组的任何一端删除元素,{$pop:{key:1}}从数组末尾删除一个元素,{$pop:{key:-1}}则从头部删除

        有时需要基于特定条件来删除元素,而不仅仅是依据位置,“$pull”可以做到,“$pull”会将所有匹配到的部分删除,如

        1
        db.lists.update({},{ "$pull" :{ "todo" : "laundry" }})
      7. 数组的定位修改器:若是数组有多个值,而我们只想对其中的一部分进行操作,有2种方法可以实现:通过位置或者定位操作符(“$”),如

        1
        2
        3
        4
        5
        #下标为0表示数组的第一个元素
        db.blog.update({ "post" :post_id},...{ "$inc" :{ "comments.0.votes" : 1 }})
        #在大多数情况下,不预先查询文档就不能知道要修改数组的下标,故MongoDB提供了定位操作符“$”,用来定位查询文档已经匹配的元素,并进行更新
        db.blog.update({ "comments.author" : "John" },...{ "$set" :{ "comments.$.author" : "Jim" }})
        #定位符只更新第一个匹配到的元素
      8. 修改器速度:$inc能就地修改,且不需要改变文档的大小,故运行非常快,而数据修改器可能更改了文档的大小,就会慢一些;MongoDB预留了些补白给文档,来适应大小变化,但若超出了原来的空间,则会分配新的空间,就会减慢速度,同时随着数组变长,MongoDB需要更长的时间来遍历整个数组,对每个数组的修改也会慢下来。

    5. upsert:是一种特殊的更新,若是没有文档符合更新条件,就会以这个条件和更新文档为基础创建一个新的文档,若匹配到了文档,则正常更新;update操作的第3个参数表示是否开启upsert,如

      1
      db.analytics.update({ "url" : "/blog" },{ "$inc" :{ "count" : 3 }},true)

      save Shell帮助程序:save是一个shell函数,可以在文档不存在时插入,存在时更新,只有一个参数:文档;若这个文档含有“_id”键,save会调用upsert,否则调用插入,如

      1
      2
      3
      var x  =  db.foo.findOne()
      x.num  =  42
      db.foo.save(x)
    6. 更新多个文档:默认情况下,更新只能对符合匹配条件的第一个文档执行操作,若使所有匹配到的文档都得到更新,可以设置update的第4个参数为true,如

      1
      db.users.update({birthday: "10/13/1978" },...{$ set :{gift: "Happy Birthday!" }},false,true)

      要知道多少文档被更新了,可以运行getLastError命令,键“n”的值就是要的数字,如

      1
      2
      db.count.update({x: 1 },{$inc:{x: 1 }},false,true)
      db.runCommand({getLastError: 1 })
    7. 返回已更新的文档:用getLastError仅能获得有限的信息,并不能返回已更新的文档,可通过findAndModify命令实现,其调用方式和普通的更新略有不同,有点慢,因为它要等待数据库的响应,如

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      ps  =  db.runCommand({ "findAndModify" :processes,
      ... "query" :{ "status" : "READY" },
      ... "sort" :{ "priority" : - 1 },
      ... "update" :{ "$set" :{ "status" : "RUNNING" }}}).value
      do_something(ps)
      db.process.update({ "_id" :ps._id},{ "$set" :{ "status" : "DONE" }})
      #findAndModify命令中每个键的对应值:
      findAndModify:字符串,集合名
      query:查询文档,用来检索文档的条件
      sort:排序结果的条件
      update:修改器文档,对所找到的文档执行的更新
      remove:布尔类型,表示是否删除文档
      new:布尔类型,表示返回的是更新前的文档还是更新后的文档,默认是更新前的文档
      #findAndModify命令的限制:
      #"update"和"remove"必须有一个,也只能有一个;
      #若匹配不到文档,则返回错误
      #一次只能处理一个文档,也不能执行upsert操作,只能更新已有文档


瞬间完成:本章讨论的3个操作(插入、删除、更新)都是瞬间完成的,因为它们都不需要等待数据库响应,只会受客户端发送的速度和网络速度的制约;这对于某些应用(如日志记录,分析数据等)是可以接受的,但对于某些应用(如付费系统)就不适用了

  1. 安全操作

    1. 若要完成电子商务系统,则需要一个“安全”版本,保证执行时检查到了错误还可以重来;

    2. 安全的版本在执行完了操作后立即运行getLastError命令,来检查是否执行成功,驱动程序会等待数据库响应,然后适当地处理错误,一般会抛出一个可被捕获的异常

    3. “安全”的代价就是性能,即便忽略客户端处理异常的开销,等待数据库响应本身的时间比只发送消息的时间多一个数量级,所以,应用程序需要权衡数据的重要性(以及丢失后的后果)及速度需求

  2. 捕获“常规”错误

    1. 安全操作也是一种调试数据库“奇怪”行为的好方法,这样可以避免很多常见的数据库使用错误

    2. 最常见的就是键重复的错误,即插入一个“_id”值已被占用的文档

请求和连接

  1. 数据库会为每一个MongoDB数据库连接创建一个队列,存放这个连接的请求

  2. 当客户端发送一个请求,会被放到队列的末尾,只有队列中的请求都执行完毕,后续的请求才会执行

  3. 所以从单个连接就可以了解整个数据库,并且它总是能读到自己写的东西

  4. 每个连接都有独立的队列,要是打开2个shell,就有2个数据库连接,在一个shell中执行插入,之后在另一个shell中执行查询不一定能得到插入的文档

  5. 使用Ruby、Python和Java驱动程序时要特别注意这种行为,因为这几种语言的驱动程序都使用了连接池











本文转自 xxrenzhe11 51CTO博客,原文链接:http://blog.51cto.com/xxrenzhe/1254097,如需转载请自行联系原作者
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
NoSQL 算法 Linux
MongoDB学习笔记(五) 集群搭建之副本集
MongoDB学习笔记(五) 集群搭建之副本集
362 0
|
NoSQL Linux MongoDB
MongoDB学习笔记(四) 集群搭建之主从复制
MongoDB学习笔记(四) 集群搭建之主从复制
534 0
|
分布式计算 NoSQL MongoDB
MongoDB学习笔记(三) 聚合
MongoDB学习笔记(三) 聚合
100 0
|
JSON NoSQL 关系型数据库
MongoDB学习笔记(二) 增删改查
MongoDB学习笔记(二) 增删改查
148 0
|
NoSQL 数据可视化 Linux
MongoDB学习笔记(一) 安装配置
MongoDB学习笔记(一) 安装配置
901 0
|
存储 缓存 NoSQL
Spring Boot2.5 实战 MongoDB 与高并发 Redis 缓存|学习笔记
快速学习 Spring Boot2.5 实战 MongoDB 与高并发 Redis 缓存
433 0
Spring Boot2.5 实战 MongoDB 与高并发 Redis 缓存|学习笔记
|
存储 SQL JSON
走进 MongoDB|学习笔记
快速学习走进 MongoDB
201 0
走进 MongoDB|学习笔记
|
存储 监控 NoSQL
MongoDB 快速入门-MongoDB 最佳实践(二)|学习笔记
快速学习 MongoDB 快速入门-MongoDB 最佳实践(二)
428 0
MongoDB 快速入门-MongoDB 最佳实践(二)|学习笔记
|
SQL 存储 分布式计算
MongoDB 聚合框架|学习笔记
快速学习 MongoDB 聚合框架
381 0
MongoDB 聚合框架|学习笔记
|
存储 JSON NoSQL
MongoDB 简介&体系结构&数据模型& | 学习笔记
快速学习 MongoDB简介&体系结构&数据模型&
151 0
MongoDB 简介&体系结构&数据模型& | 学习笔记