b)、使用选择器更新(重点)
1、$set修改器
执行特殊更新操作;可以修改内嵌文档;甚至可以更改键的类型;
Ⅰ、假设需求改了,我们需要为为所有用户添加一个”hobby“的属性用于存放用户的喜好,那么我们可以这样做:
db.users.update({},{$set:{"hobby":"read"}}) //这样做是错的,哈哈。。
更新后的文档如下:
切记:update方法只会更新它匹配到的第一个文档对象,所以这个操作只会将名字为”wjg“的用户添加一个”hobby“属性,其它对象不会添加
正确方式如下:
db.users.update({},{$set:{"hobby":"write"}},false,true) //第三个参数为是否启用特殊更新,第四个为是否更新所有匹配的文档;
这俩参数默认都为false
更新后的文档如下:
可以看到我们成功更新了五个文档对象
Ⅱ、假设我们需求又变了,老板说了,每个用户的爱好会有多个。那么简单,因为我们可以直接将string类型的hobby属性改成string数组类型的
db.users.update({"_id":0},{"$set":{"hobby":["write","read","paly ping-pong"]}}) //将_id为0的hobby属性更新为数组类型的
Ⅲ、然后我们发现tom压根就没有爱好,那么我们可以使用$unset修改器将其删除
db.users.update({"_id":1},{"$unset":{"hobby":1}}) //1表示彻底删除这个键值对
Ⅳ、现在已经过去一年了,我们是时候把所有用户的年龄加一岁了。这时$inc上场
db.users.update({},{"$inc":{"age":1}},false,true) //别忘了将第四个参数置为true
注:$inc修改器只针对数字类型,如果是string或者其他类型的会提示报错:
提示无法将$inc应用到非数字类型上,并且给出错误位置:”_id“为2的文档;
我们将joe的age改为数字类型的重新执行一次,就可以成功啦!
Ⅴ、过了一段时间,jack又喜欢上了游泳,那么我们可以用$push这样搞:
db.users.update({"_id":0},{"$push":{"hobby":"swim"}}) //hobby必须是一个数组,所以你在其他文档上使用是不会成功的
Ⅵ、然而jack不喜欢读书了,我们就用$pull来移除“read”元素
db.users.update({"_id":0},{"$pull":{"hobby":"read"}}) //它会移除数组中所有匹配到的“read”元素
另外:db.users.update({"_id":0},{"$pop":{"hobby":1}}) //表示移除hobby中的最后一个元素,为-1表示移除第一个元素
不知道大家有没有发现,“_id”为0的文档从第二的位置被移动到了数据集的末尾,这是因为该文档尺寸变大的原因导致的,
原先的位置已经容不下它了!
那么这就引出了另外一个概念:填充因子,它是MongoDB为每个新文档预留的增长空间。上边的这种情况就会使填充因子增加。
移动文档是一个非常缓慢的操作,尽量让填充因子的值接近1;
通过db.users.stats()查看该数据集信息,“paddingFactor”即为填充因子的大小;
三、删除
删除文档相对来说就简单了许多
1、单一删除
给定一个查询参数,只要符合条件的,都会被删除
db.users.remove({"_id":{"$lte":1}}) //删除“_id”的值小于等于1的所有文档
返回结果如下:
WriteResult({"nRemoved":2}) //成功删除了两个文档
2、清空整个数据集
db.users.remove()
如果数据较多的话,用db.users.drop()会明显提升删除速度
注:删除都是不可逆的,不能撤销,也不能恢复,所以要谨慎使用;
清空数据集的时候集合本身并不会被删除,也不会删除集合的元信息;
四、未解决问题
1、先取出来再更新,使用查询条件取出来的数据都无法用游标去获取值,但是用findOne获取的一个文档对象就可以。。。
如果哪位大神知道的话麻烦告诉小弟一下,多谢、、、哈哈。。
最后一个问题已经找到,原因如下:
第一个find操作虽然获取的只是一个文档对象,看似和下边用findOne是一样的效果,但是在MongoDB的shell中第一个的结果集是被默认为多个文档集合,所以它无法判断你想获取的是哪个文档的age。