小言_互联网的博客

mongo中增删改的高阶用法

237人阅读  评论(0)

之前的博文 ”MongoDB基本的增删改“介绍了mongodb如何处理基本的修改操作, 但是对于一些相对复杂的操作并没有说,比如批量、优化等。本文就主要讲一下如何进行这些处理

1. 批量插入
  • insertMany
    shell中,可以直接用这个函数实现,语法与insert类似

    db.peo.insert({_id:11,name:'z1'}) // 单条插入
    db.peo.insertMany([{_id:12,name:'z2'},{_id:13,name:'z3'}])
    
  • 批量插入,发生错误,结果
    注意,批量插入的时候,需要关注的一个点就是 ”多个document,如果其中一个失败,剩下的会插入成功么?“ 。 对于mysql来说,在一个事务中出错,会整个回滚,具体的测试案例 可以参考 ”mysql批量插入语句执行失败的话,是部分失败还是全部失败“ 。

    对于mongodb来讲,实际上一个失败了,并不影响之前成功的, 这里测试一下,我们知道重复Id是无法插入的,因此我们造多个document,在中间选择一条重复id, 查看一下 :

    • 错误之前的内容是否还在 ?
    • 错误之后的内容是否插入
    db.peo.insertMany([
    		{_id:20,name:'20'},
    		{_id:21,name:'21'},
    		{_id:22,name:'22'},
    		{_id:23,name:'23'},
    		{_id:23,name:'aaa'},
    		{_id:24,name:'24'},
    		{_id:25,name:'25'}
    		])
    

    执行汇会报错,结果如下

    BulkWriteError({
    	"writeErrors" : [
    		{
    			"index" : 4,
    			"code" : 11000,
    			"errmsg" : "E11000 duplicate key error collection: demo.peo index: _id_ dup key: { : 23.0 }",
    			"op" : {
    				"_id" : 23,
    				"name" : "aaa"
    			}
    		}
    	],
    	"writeConcernErrors" : [ ],
    	"nInserted" : 4, // 注意 : 这里显示插入成功了4条
    	"nUpserted" : 0,
    	"nMatched" : 0,
    	"nModified" : 0,
    	"nRemoved" : 0,
    	"upserted" : [ ]
    })
    

    查看一下,发现的确插入了四条

    >  db.peo.find()
    { "_id" : 20, "name" : "20" }
    { "_id" : 21, "name" : "21" }
    { "_id" : 22, "name" : "22" }
    { "_id" : 23, "name" : "23" }
    

    证明 : 多条插入:

    • 错误之前的document会插入成功
    • 错误之后的,不再插入
  • 插入校验
    实际上,mongoDB插入时,会对数据做基本的检查: 如下 , 但这并不能阻止插入非法数据,因此建议是用受信任的源(比如Java驱动程序搭建的应用服务器),在插入之间,先利用相关语言(比如java)先检查数据合理性

    • 大小不可超过16M, (可以用Object.bsonsize(document)查看)
    • _id字段不存,就添加一个
2. 原子性修改器
  • 概念
    举例说明,一个document中,我们只想修改其中的一个字段的数据,比如下边的age,就需要原子性修改器。

    {
    	_id : 1,
    	age : 14,
    	name : 'zhangsan'
    }
    

    比如,过了一年,张三又大了一岁,可以采用$inc

    db.people.updateOne({'_id':1},{"$inc":{"age":1}})
    
  • 常用的原子性修改器

    • “$set” :
      指定一个字段的值,如果对应字段不存在,就创建; 可以修改键的类型 。 比如,张三变大了,现在多了一个喜欢人叫 宝贝, 就可以用$set

      >db.people.updateOne({'_id':1},{"$set":{"lover":'宝贝'}})
      > db.people.find()
      { "_id" : 1, "age" : 14, "name" : "zhangsan", "lover" : "宝贝" }
      

      上边代码, 证明了$set 对应字段不存在,会新创建对应key
      之后呢,时间变久了,张三,喜欢的妹子开始是一个,后来变成了数组,如下

      >db.people.updateOne({'_id':1},{"$set":{"lover":['宝贝','小姐姐','娃娃']}})
      > db.people.find()
      { "_id" : 1, "age" : 14, "name" : "zhangsan", "lover" : [ "宝贝", "小姐姐", "娃娃" ] }
      

      上边代码证明 : $set 可以修改相关字段类型,(字符串变成了数组)

    • ”$inc“
      增加和减少(增加负数), 只用于整形、长整形、浮点,用在其他类型上,操作失败 ,这里就不多介绍了

    • 数组修改器

      • “$push” :
        向已有的数组末尾加入一个元素,没有就新建一个数组 。
        > db.people.find()
        { "_id" : 1, "age" : 14, "name" : "zhangsan", "lover" : [ "娃娃" ] }
        > db.people.updateOne({_id:1},{"$push":{"lover":"honey"}})
        { "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
        > db.people.find()
        { "_id" : 1, "age" : 14, "name" : "zhangsan", "lover" : [ "娃娃", "honey" ] }
        
        注意 : 如果操作的字段不是数组,会报错 . 比如李四只爱一人,保存的是一个字符串,要是给他push爱人,会报错
        The field 'lover' must be an array but is of type string in document {_id: 2.0}"
        
      • ”$pop“
        和push相对,pop弹出元素,语法
         {"$pop":{"key" : 1}} // 把key从尾部删除
         {"$pop":{"key" : -1}} // 把key从头部删除
        
      • ”$pull“
        和pop相比,pull删除符合条件的所有数组的元素,语法
         {"$pull":{"lover" :'宝宝'}} // 把宝宝从数组中删除
        
3. 数组修改器

数组修改器,比如“$push”、“$pop”等,上边简单介绍了基本用法,实际上,数组修改器可以有很多丰富的用法,比如下边,可以基于位置修改数组中对象属性

  • 1 基于位置修改数组中对象属性
    比如,张三喜欢的人,咱们丰富一下,不止记录名字,记录一个对象

    	{
    		_id : 1,
    		age : 14,
    		name : 'zhangsan',
    		lover :  [
    				{name : '宝贝',age : 21},
    				{name : '宝贝2',age : 23}
    			] 
    		}
    

    基于位置的数组修改器, 比如 修改张三喜欢的 第二个人的年龄,就可以用基于位置的数组修改器,例子如下

    db.people.update({_id:1},{"$inc":{"lover.1.age":1}})
    > db.people.find()
    { "_id" : 1, "age" : 14, "name" : "zhangsan", "lover" : [ { "name" : "宝贝", "age" : 21 }, { "name" : "宝贝2", "age" : 24 } ] }
    

    上边代码,就是基于位置的

     "lover.1.age":  表示lovers数组第二个元素 (可能是个对象)的某一属性(age)
    

    如果不知道具体的位置,可以用下边的方式,查找,

    { "lover.$.age":23 }
    

    如果存在多个 相同的,只修改查询到的第一条

4. 更新多个文档
  • updateMany 可以利用这个方法实现更新多个文档, 该方法是将所有匹配的记录都修改
5. 写入安全机制

写入安全 (write concern ) :
之前博文,在讲述基础增删改时,提到它们选项中,有此选择,如下

{
      writeConcern: <document>,
      collation: <document>
   }

这是一种客户端设置,用于控制写入的安全级别。增删改 ,在默认情况下,都会一直等待数据库响应 (写入是否成功),然后才会继续执行,通常,遇到错误时,客户端会抛出一个异常

两种最基本的写入安全机制 : 应答式写入 (acknowledged write)、非应答式(unacknowledged write)。 默认是应答式吸入,数据库会给出响应,告诉你写入操作是否成功 , 非应答式不返回任何响应

默认选择非应答式,但有些不重要的数据, 比如日志、批量操作, 没必要关注数据响应,所以可以采用非应答式


转载:https://blog.csdn.net/qq_23143621/article/details/101220680
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场