之前的博文 ”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” :
向已有的数组末尾加入一个元素,没有就新建一个数组 。
注意 : 如果操作的字段不是数组,会报错 . 比如李四只爱一人,保存的是一个字符串,要是给他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" ] }
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" :'宝宝'}} // 把宝宝从数组中删除
- “$push” :
-
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