咱们在前面的文章中提到过文档的基本的增删改查操做,MongoDB中提供的增删改查的语法很是丰富,本文咱们主要来看看更新都有哪些好玩的语法。 shell
本文是MongoDB系列的第四篇文章,了解前面的文章有助于更好的理解本文:数组
1.Linux上安装MongoDB
2.MongoDB基本操做
3.MongoDB数据类型函数
假设个人集合中如今存了以下一段数据:spa
{ "_id" : ObjectId("59f005402844ff254a1b68f6"), "name" : "三国演义", "authorName" : "罗贯中", "authorGender" : "男", "authorAge" : 99.0 }
这是一本书,有书名和做者信息,可是做者是一个独立的实体,因此我想将之提取出来,变成下面这样:3d
{ "_id" : ObjectId("59f005402844ff254a1b68f6"), "name" : "三国演义", "author" : { "name" : "罗贯中", "gender" : "男", "age" : 99.0 } }
我能够采用以下操做: code
另一个问题是更新时,MongoDB只会匹配第一个更新的文档,假设个人MongoDB中有以下数据:blog
{ "_id" : ObjectId("59f00d4a2844ff254a1b68f7"), "x" : 1 } { "_id" : ObjectId("59f00d4a2844ff254a1b68f8"), "x" : 1 } { "_id" : ObjectId("59f00d4a2844ff254a1b68f9"), "x" : 1 } { "_id" : ObjectId("59f00d4a2844ff254a1b68fa"), "x" : 2 }
我想把全部x为1的数据改成99,咱们很容易想到以下命令:排序
db.sang_collect.update({x:1},{x:99})
但咱们发现执行结果倒是这样:图片
{ "_id" : ObjectId("59f00d4a2844ff254a1b68f7"), "x" : 99 } { "_id" : ObjectId("59f00d4a2844ff254a1b68f8"), "x" : 1 } { "_id" : ObjectId("59f00d4a2844ff254a1b68f9"), "x" : 1 } { "_id" : ObjectId("59f00d4a2844ff254a1b68fa"), "x" : 2 }
即只有第一条匹配的结果被更新了,其余的都没有变化。这是MongoDB的更新规则,即只更新第一条匹配结果。若是咱们想将全部x为1的更新为x为99,能够采用以下命令:文档
db.sang_collect.update({x:1},{$set:{x:99}},false,true)
首先咱们将要修改的数据赋值给$set,$set是一个修改器,咱们将在下文详细讲解,而后后面多了两个参数,第一个false表示若是不存在update记录,是否将咱们要更新的文档做为一个新文档插入,true表示插入,false表示不插入,默认为false,第二个true表示是否更新所有查到的文档,false表示只更新第一条记录,true表示更新全部查到的文档。
不少时候咱们修改文档,只是要修改文章的某一部分,而不是所有,可是如今我面临这样一个问题,假设我有以下一个文档:
{x:1,y:2,z:3}
我如今想把这个文档中x的值改成99,我可能使用以下操做:
db.sang_collect.update({x:1},{x:99})
可是更新结果却变成了这样:
{ "_id" : ObjectId("59f02dce95769f660c09955b"), "x" : 99 }
以下图:
MongoDB帮我把整个文档更新了!要解决这个问题,咱们能够使用修改器。
$set能够用来修改一个字段的值,若是这个字段不存在,则建立它。以下:
若是该字段不存在,则建立,以下:
也能够利用$unset删除一个字段,以下:
$set也能够用来修改内嵌文档,还以刚才的书为例,以下:
{ "_id" : ObjectId("59f042cfcafd355da9486008"), "name" : "三国演义", "author" : { "name" : "罗贯中", "gender" : "男" } }
想要修改做者的名字,操做以下:
db.sang_collect.update({name:"三国演义"},{$set:{"author.name":"明代罗贯中"}})
修改结果以下:
{ "_id" : ObjectId("59f042cfcafd355da9486008"), "name" : "三国演义", "author" : { "name" : "明代罗贯中", "gender" : "男" } }
$inc用来增长已有键的值,若是该键不存在就新建立一个。好比我想给上文的罗贯中增长一个年龄为99,方式以下:
db.sang_collect.update({name:"三国演义"},{$inc:{"author.age":99}})
执行结果以下:
{ "_id" : ObjectId("59f042cfcafd355da9486008"), "name" : "三国演义", "author" : { "name" : "明代罗贯中", "gender" : "男", "age" : 99.0 } }
加入我想给罗贯中增长1岁,执行以下命令:
db.sang_collect.update({name:"三国演义"},{$inc:{"author.age":1}})
这是会在现有值上加1,结果以下:
{ "_id" : ObjectId("59f042cfcafd355da9486008"), "name" : "三国演义", "author" : { "name" : "明代罗贯中", "gender" : "男", "age" : 100.0 } }
注意$inc只能用来操做数字,不能用来操做null、布尔等。
数组修改器有好几种,咱们分别来看。
$push能够向已有数组末尾追加元素,要是不存在就建立一个数组,仍是以咱们的上面的book为例,假设book有一个字段为comments,是一个数组,表示对这个book的评论,咱们能够使用以下命令添加一条评论:
db.sang_collect.update({name:"三国演义"},{$push:{comments:"好书666"}})
此时不存在comments字段,系统会自动帮咱们建立该字段,结果以下:
{ "_id" : ObjectId("59f042cfcafd355da9486008"), "name" : "三国演义", "author" : { "name" : "明代罗贯中", "gender" : "男", "age" : 100.0 }, "comments" : [ "好书666" ] }
此时咱们能够追加评论,以下:
db.sang_collect.update({name:"三国演义"},{$push:{comments:"好书666啦啦啦啦"}})
结果以下:
{ "_id" : ObjectId("59f042cfcafd355da9486008"), "name" : "三国演义", "author" : { "name" : "明代罗贯中", "gender" : "男", "age" : 100.0 }, "comments" : [ "好书666", "好书666啦啦啦啦" ] }
若是想一次添加3条评论,能够结合$each一块儿来使用,以下:
db.sang_collect.update({name:"三国演义"},{$push:{comments:{$each:["111","222","333"]}}})
结果以下:
{ "_id" : ObjectId("59f042cfcafd355da9486008"), "name" : "三国演义", "author" : { "name" : "明代罗贯中", "gender" : "男", "age" : 100.0 }, "comments" : [ "好书666", "好书666啦啦啦啦", "111", "222", "333" ] }
咱们能够使用$slice来固定数组的长度,假设我固定数组的长度为5,若是数组中的元素不足5个,则所有保留,若是数组中的元素超过5个,则只会保留最新的5个,以下:
db.sang_collect.update({name:"三国演义"},{$push:{comments:{$each:["444","555"],$slice:-5}}})
注意$slice的值为负数,运行结果以下:
{ "_id" : ObjectId("59f042cfcafd355da9486008"), "name" : "三国演义", "author" : { "name" : "明代罗贯中", "gender" : "男", "age" : 100.0 }, "comments" : [ "111", "222", "333", "444", "555" ] }
咱们还能够在清理以前使用$sort对数据先进行排序,而后再清理好比我有一个class文档,以下:
{ "_id" : ObjectId("59f07f3649fc5c9c2412a662"), "class" : "三年级二班" }
如今向这个文档中插入student,每一个student有姓名和成绩,而后按照成绩降序排列,只要前5条数据,以下:
db.sang_collect.update({class:"三年级二班"},{$push:{students:{$each:[{name:"张一百",score:100},{name:"张九九",score:99},{name:"张九八",score:98}],$slice:5,$sort:{score:-1}}}})
$sort的取值为-1和1,-1表示降序,1表示升序。
上面的命令执行两次以后(即插入两次),结果以下:
{ "_id" : ObjectId("59f07f3649fc5c9c2412a662"), "class" : "三年级二班", "students" : [ { "name" : "张一百", "score" : 100.0 }, { "name" : "张一百", "score" : 100.0 }, { "name" : "张九九", "score" : 99.0 }, { "name" : "张九九", "score" : 99.0 }, { "name" : "张九八", "score" : 98.0 } ] }
$slice和$sort不能只和$push一块儿使用,还要加上$each。
咱们能够在插入的时候使用$addToSet,表示要插入的值若是存在则不插入,不然插入,以下:
db.sang_collect.update({name:"三国演义"},{$addToSet:{comments:"好书"}})
上面的命令执行屡次以后,发现只成功插入了一条数据。也能够将$addToSet和$each结合起来使用,以下:
db.sang_collect.update({name:"三国演义"},{$addToSet:{comments:{$each:["111","222","333"]}}})
$pop能够用来删除数组中的数据,以下:
db.sang_collect.update({name:"三国演义"},{$pop:{comments:1}})
1表示从comments数组的末尾删除一条数据,-1表示从comments数组的开头删除一条数据。
使用$pull咱们能够按条件删除数组中的某个元素,以下:
db.sang_collect.update({name:"三国演义"},{$pull:{comments:"444"}})
表示删除数组中值为444的数据。
既然是数组,咱们固然能够经过下标来访问,以下一行操做表示将下标为0的(第一个comments)comments修改成999:
db.sang_collect.update({name:"三国演义"},{$set:{"comments.0":"999"}})
但是有的时候我并不知道我要修改的数据处于数组中的什么位置,这个时候能够使用$符号来解决:
db.sang_collect.update({comments:"333"},{$set:{"comments.$":"333-1"}})
查询条件查出来333的下标,$符号就代码这个下标,而后经过$符号就能将之修改。
save是shell中的一个函数,接收一个参数,这个参数就是文档,若是文档中有_id
参数save会执行更新操做,不然执行插入操做,使用save操做咱们能够方便的完成一些更新操做。
相似于以下命令则表示一个插入操做(由于没有_id
):
db.sang_collect.save({x:111})
好了,MongoDB的更新操做咱们就先介绍这么多,有问题欢迎留言讨论。
参考资料:
1.《MongoDB权威指南第2版》
更多资料请关注公众号: