MongoDB最基础的部分已经看的差不多了,作为数据库来说做的最多的还是对数据库数据的操作。本文将介绍MongoDB中一下三点
- 向集合中添加新文档
- 从集合中删除文档
- 更新现有文档
插入并保存文档
插入一条记录
> db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "username" : "wangwu", "password " : "121212", "tel" : "121212" } > db.user.insert({username:'aaa',password:'bbb',tel:'123123123'}); > db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "username" : "wangwu", "password " : "121212", "tel" : "121212" } { "_id" : ObjectId("51b91edc32b7955cd61dbc8e"), "username" : "aaa", "password" : "bbb", "tel" : "123123123" } >
操作为文档增加了一个“_id”,然后保存到了MongoDB中
> db.user.insert({_id:'12345678',username:'aaa',password:'bbb',tel:'123123123'}) ; > db.user.find(); { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "username" : "wangwu", "password " : "121212", "tel" : "121212" } { "_id" : ObjectId("51b91edc32b7955cd61dbc8e"), "username" : "aaa", "password" : "bbb", "tel" : "123123123" } { "_id" : "12345678", "username" : "aaa", "password" : "bbb", "tel" : "123123123 " } >
如果我们自己定义了一个_id的话,数据库就不在自己生存,可以看到数据库自己生成的是ObjectId。
批量插入
如果要插入多个文档,批量要快一些。批量插入能传递一个由文档构成的数组给数据库
一次发送多个文档会提高插入数度。一次插入需要建立一个TCP链接。批量提交,会比多次提交数据少建立TCP连接,避免了零碎的请求开销。而且批量提交只会有一个文件头信息,数据不用多次的处理文件头。
用数组的方式一次插入两条数据
> db.user.insert([{username:'aaa',password:'bbb',tel:'123123123'},{username:'bbb ',password:'ccc',tel:'123123234'}]); > db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "username" : "wangwu", "password " : "121212", "tel" : "121212" } { "_id" : ObjectId("51b91edc32b7955cd61dbc8e"), "username" : "aaa", "password" : "bbb", "tel" : "123123123" } { "_id" : "12345678", "username" : "aaa", "password" : "bbb", "tel" : "123123123 " } { "_id" : ObjectId("51b920ca32b7955cd61dbc8f"), "username" : "aaa", "password" : "bbb", "tel" : "123123123" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "username" : "bbb", "password" : "ccc", "tel" : "123123234" } >
插入原理和作用
当执行插入事,使用的驱动会将数据转换为BSON的形式,将其送入数据库。数据库解析BSON,检验是否有_id,和文档的大小,除此之外,文档不做别的数据验证,简单的将数据存入数据库中。
ps.大于4M的文档是不能存入数据库中的。
删除文档
删除文档用
> db.user.remove()
如果remove不传入任何参数,会删除所有文档,但不会删除集合本身,原索引也会保留。
如果给定参数,只有符合条件的才会删除
> db.user.remove({username:'aaa'}) > db.user.find(); { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "username" : "wangwu", "password " : "121212", "tel" : "121212" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "username" : "bbb", "password" : "ccc", "tel" : "123123234" } >
删除速度
删除文档通常会很快,但是要清除整个集合,直接删除集合会更快
更新文档
文档存入数据库后,就可以用update方法来修改它,update有两个参数一个是查询文档,找出需要更新的文档。一个是修改文档,描述对找到的文档做哪些修改
更新操作是原子的,若是两个更新同时发生,先到达服务器的先执行。
文档替换
更新最简单的就是完全用一个新文档替代匹配文档。比如我们将username为bb的文档替换为如下
> db.user.update({username:'bbb'},{password:'abc'}); > db.user.find(); { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "username" : "wangwu", "password " : "121212", "tel" : "121212" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } >
我们发现文档结构被替换成了
{ "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } >
也就是说这样的替换是直接替换文档,而不是做修改。在大的改动的情况下,使用文档变更可以直接替换文档,但有时候这样却不是我们想要的,我们只是希望修改password而不变动其他的内容
使用修改器
通常文档只会有部分要更新。利用原子的修改器,可以用来部分更新。
$set修改器
$set用来指定一个键的值,如果这个键不存在,就创建它。下面我们修改username为wangwu的password的值
> db.user.find(); { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "username" : "wangwu", "password " : "121212", "tel" : "121212" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } > db.user.update({username:'wangwu'},{$set:{password:'abcdef'}}); > db.user.find(); { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "username" : "wangwu", "password " : "abcdef", "tel" : "121212" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } >
$unset修改器
$unset来删除一个键,比如删除username为wangwu的tel键
> db.user.update({username:'wangwu'},{$unset:{tel:1}}); > db.user.find(); { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "password" : "abcdef", "username " : "wangwu" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } >
$inc修改器
$inc用来增加已有的键值,或者在键值不存在时创建。
现在我们需要一个age的值
现在给age执行$inc
> db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "password" : "abcdef", "username " : "wangwu" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } > db.user.update({username:'wangwu'},{$inc:{age:1}}); > db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 1, "password" : "abcdef" , "username" : "wangwu" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } > db.user.update({username:'wangwu'},{$inc:{age:1}}); > db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "password" : "abcdef" , "username" : "wangwu" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } >
这里执行了两次$inc,age第一次创建了一个值为1的键值,然后自加了1.
$inc键的值必须为数字,如果尝试修改成其他类型就会出现如下错误
> db.user.update({username:'wangwu'},{$inc:{age:'abc'}});
Modifier $inc allowed for numbers only
>
数组修改器
数组修改器只能用于数组。
$push会像已有的数组末尾假如一个元素
$pop会从头部删除一个元素
> db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "password" : "abcdef" , "username" : "wangwu" } { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } > db.user.update({username:'wangwu'},{$push:{arr:1}}); > db.user.find() { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "arr" : [ 1 ], "pass word" : "abcdef", "username" : "wangwu" } > db.user.update({username:'wangwu'},{$push:{arr:2}}); > db.user.find() { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "arr" : [ 1, 2 ], " password" : "abcdef", "username" : "wangwu" } > db.user.update({username:'wangwu'},{$pop:{arr:2}}); > db.user.find() { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "arr" : [ 1 ], "pass word" : "abcdef", "username" : "wangwu" } > db.user.update({username:'wangwu'},{$pop:{arr:2}}); > db.user.find() { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "arr" : [ ], "passwor d" : "abcdef", "username" : "wangwu" }
数组的定位修改器
若是数组中多个值,我们只想修改其中的部分值,有两种方法操作数组中的值:通过位置和定位操作符($)
> db.user.update({username:'wangwu'},{$set:{'arr.1':1}}); > db.user.find() { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "arr" : [ 2, 1, 3, 4 ], "password" : "a", "username" : "wangwu" } > db.user.update({username:'wangwu'},{$set:{'arr.$':1}}); Cannot apply the positional operator without a corresponding query field contain ing an array. > db.user.update({'arr.1':1},{$set:{'arr.$':1}}); > db.user.update({'arr.1':1},{$set:{'arr.$':3}}); > db.user.find() { "_id" : ObjectId("51b920ca32b7955cd61dbc90"), "password" : "abc" } { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "arr" : [ 2, 3, 3, 4 ], "password" : "a", "username" : "wangwu" } >
使用位置可以直接修改指定位置的数据,使用定位操作符是在查询的时候不知道该位置的时候使用,这个时候需要注意的是查询username的时候,使用$会报出错误。也就是查询出来的值不是数组,所以不能用$来指定
upsert
upsert是一个特殊的更新。当没有文档符合更新条件,就会以这个条件创建新的文档。当update的第三个参数设置为true的时候,为upsert模式
> db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "arr" : [ 2, 3, 3, 4 ], "password" : "a", "username" : "wangwu" } > db.user.update({age:1},{$set:{abc:123}},true) > db.user.find() { "_id" : ObjectId("51b28f74b73ec06e42c91598"), "age" : 2, "arr" : [ 2, 3, 3, 4 ], "password" : "a", "username" : "wangwu" } { "_id" : ObjectId("51ba745f5fdf5d2d7426eb35"), "abc" : 123, "age" : 1 } >
更新多个文档
默认情况下,更新只能对符合匹配条件的第一个文档操作,要是有多个文档符合条件,其余的文档就没有变化。要使所有的文档都得到更新,可以设置update的第四个参数为true
返回已经更新的文档
用getLastError只能获取有限的信息,并不能返回更新的文档。这个可以通过findAndModify来做到。
安全操作
MongoDB选中选择不安全的版本作为默认操作,如果需要判断状态,在执行完操作后立即运行getLastError,来检查是否成功。
如果不考虑安全性的问题,就无序调用getLastError
把重要的数据用安全的方式操作
请求和连接
数据库为MongoDB创建了一个队列,存放这个连接请求。当客户端发送一个请求,会被放到队列的末尾。只有队列中的请求都执行完毕,后续的请求才会执行。每个连接都有独立的队列。