如此明媚春光,正是打望好时节,恰周末楼下周边溜达,热,遂归。来折腾我的mongodb学习计划。现在应该是看到update部分了,参考《MongoDB权威指南》
update
update({},{},boolean,boolean)
shell命令update接受四个参数
1、查询文档:找出需要更新的文档
2、修改器:描述对文档的修改
3、upsert:没有文档符合更新条件,则创建改记录。默认false不支持
4、更新默认只会对满足条件的第一条记录更新,支持批量设置true
1、采用shell命令更新 ,首先获取查询结果,对结果进行修改再操作
获取一个document对象
> var user = db.users.findOne() > user { "_id" : ObjectId("4f62ef1cb678c1a3326549e6"), "name" : "robin", "age" : 30, "friends" : 32 }
新增address属性,并更新操作
> user.address = {"city":"chengdu","street":"asdasdfas"} { "city" : "chengdu", "street" : "asdasdfas" } > db.users.update({"name":"robin"},user) > db.users.findOne() { "_id" : ObjectId("4f62ef1cb678c1a3326549e6"), "name" : "robin", "age" : 30, "friends" : 32, "address" : { "city" : "chengdu", "street" : "asdasdfas" } }
其他的一些操作
> delete user.age true > user { "_id" : ObjectId("4f62ef1cb678c1a3326549e6"), "name" : "robin", "friends" : 32, "address" : { "city" : "chengdu", "street" : "asdasdfas" } }
书中提到了对批量数据的修改,在查询时返回了多条记录,不能直接调用update,是由于在update时会匹配多条记录,而实际更新的会与记录中的其他"_id"不一致。但是在我测试的版本2.0.2中,貌似没有这样的错误发生,难道已经改变了update策略:
#根据name查找有四条记录 > db.users.find({"name":"robin"}) { "_id" : ObjectId("4f62ef1cb678c1a3326549e6"), "name" : "robin", "age" : 31, "friends" : 32, "address" : { "city" : "chengdu", "street" : "asdasdfas" } } { "_id" : ObjectId("4f62f5b8b678c1a3326549e7"), "name" : "robin", "age" : 20, "foo" : "bar" } { "_id" : ObjectId("4f62f5c6b678c1a3326549e8"), "name" : "robin", "age" : 30, "foo" : "bar" } { "_id" : ObjectId("4f62f5cdb678c1a3326549e9"), "name" : "robin", "age" : 40, "foo" : "bar" } #只选取一条,并对其属性进行设置 > robin = db.users.findOne({"name":"robin"}) { "_id" : ObjectId("4f62ef1cb678c1a3326549e6"), "name" : "robin", "age" : 31, "friends" : 32, "address" : { "city" : "chengdu", "street" : "asdasdfas" } } > robin.age++ 31 > db.users.update({"name":"robin"}, robin) #查看结果只有第一条已经改变,但整个过程中并没有报错 > db.users.find() { "_id" : ObjectId("4f62ef1cb678c1a3326549e6"), "name" : "robin", "age" : 32, "friends" : 32, "address" : { "city" : "chengdu", "street" : "asdasdfas" } } { "_id" : ObjectId("4f62f5b8b678c1a3326549e7"), "name" : "robin", "age" : 20, "foo" : "bar" } { "_id" : ObjectId("4f62f5c6b678c1a3326549e8"), "name" : "robin", "age" : 30, "foo" : "bar" } { "_id" : ObjectId("4f62f5cdb678c1a3326549e9"), "name" : "robin", "age" : 40, "foo" : "bar" }
2、使用修改器修改
就是指前面update中的第二个参数,这里包括一系列的命令。下面就各个命名来分别说明
- $set
$set用来指定一个键的值,如果不存在就创建
> db.users.findOne() { "_id" : 1, "name" : "robin", "age" : 30, "gender" : "male" } #修改age的值和新增属性foo > db.users.update({"name":"robin"},{"$set":{"age":40, "foo":"bar"}}) > db.users.findOne() { "_id" : 1, "age" : 40, "foo" : "bar", "gender" : "male", "name" : "robin" } #修改属性的类型 > db.users.update({"name":"robin"},{"$set":{"age":"zzzz", "foo":["aaaa","bbbbb"]}}) > db.users.findOne() { "_id" : 1, "age" : "zzzz", "foo" : [ "aaaa", "bbbbb" ], "gender" : "male", "name" : "robin" } #修改内嵌文档 > db.users.update({"name":"robin"},{"$set":{"address":{"city":"chengdu", "street":"aaaaaaaaaa"}}}) > db.users.findOne() { "_id" : 1, "address" : { "city" : "chengdu", "street" : "aaaaaaaaaa" }, "age" : "zzzz", "foo" : [ "aaaa", "bbbbb" ], "gender" : "male", "name" : "robin" } > db.users.update({"name":"robin"},{"$set":{"address.street":"bbbbbbbbbbbbbbbb"}}) > db.users.findOne() { "_id" : 1, "address" : { "city" : "chengdu", "street" : "bbbbbbbbbbbbbbbb" }, "age" : "zzzz", "foo" : [ "aaaa", "bbbbb" ], "gender" : "male", "name" : "robin" }
- $unset
用来移除一个文档的属性
> db.users.findOne() { "_id" : 1, "address" : { "city" : "chengdu", "street" : "bbbbbbbbbbbbbbbb" }, "age" : "zzzz", "foo" : [ "aaaa", "bbbbb" ], "gender" : "male", "name" : "robin" } > db.users.update({"name":"robin"},{"$unset":{"foo":1,"address":-1}}) > db.users.findOne() { "_id" : 1, "age" : "zzzz", "gender" : "male", "name" : "robin" }
这里属性后面的数字该是什么呢,貌似没什么限制
#正数负数都试过了 > db.users.update({"name":"robin"},{"$unset":{"age":0,"address":-1}}) > db.users.findOne() { "_id" : 1, "gender" : "male", "name" : "robin" } #把查找条件也给unset了 > db.users.update({"name":"robin"},{"$unset":{"name":0,"address":-1}}) > db.users.findOne() { "_id" : 1, "gender" : "male" }
- $inc
增加或减少,这个只针对文档类型为整数、长整数或双精度浮点数。如果修改的键不存在则创建,其值为指定的数值。否则在该键上做相应的增加或减少
> db.users.find() { "_id" : ObjectId("4f630319b678c1a3326549ea"), "address" : { "city" : "chengdu", "street" : "bbbbbbbbbbbbbbbb" }, "age" : "zzzz", "gender" : "male", "name" : "robin" } #当age不是数值类型时会报错 > db.users.update({"name":"robin"},{"$inc":{"age":10}}) Cannot apply $inc modifier to non-number #修改为数值类型 > db.users.update({"name":"robin"},{"$set":{"age":10}}) > db.users.find({"name":"robin"}) { "_id" : ObjectId("4f630319b678c1a3326549ea"), "address" : { "city" : "chengdu", "street" : "bbbbbbbbbbbbbbbb" }, "age" : 10, "gender" : "male", "name" : "robin" } #同时更新,age键存在增加10,foo键不存在,创建foo并设置为30。如果要减少,只需要为负数即可 > db.users.update({"name":"robin"},{"$inc":{"age":10, "foo":30}}) > db.users.find({"name":"robin"}) { "_id" : ObjectId("4f630319b678c1a3326549ea"), "address" : { "city" : "chengdu", "street" : "bbbbbbbbbbbbbbbb" }, "age" : 20, "foo" : 30, "gender" : "male", "name" : "robin" }
- $push
数组修改器,会向已有的数组末尾加入一元素,没有则创建新的数组(注意是数组,最开始看到时我还在想用set也可以实现,当然其set的值本身就是一个数组例外)
> db.blog.insert({"title":"mongodb learn","owner":"duuuu","content":"content....."}) > db.blog.findOne() { "_id" : ObjectId("4f636a2b3c82ae09f9857f29"), "title" : "mongodb learn", "owner" : "duuuu", "content" : "content....." } #插入一条评论,将会创建comments键,并为数组结构 > db.blog.update({"owner":"duuuu"},{"$push":{"comments":{"name":"joe", "email":"mongodb@sample","content":"good"}}}) > db.blog.findOne() { "_id" : ObjectId("4f636a2b3c82ae09f9857f29"), "comments" : [ { "name" : "joe", "email" : "mongodb@sample", "content" : "good" } ], "content" : "content.....", "owner" : "duuuu", "title" : "mongodb learn" } #继续插入 > db.blog.update({"owner":"duuuu"},{"$push":{"comments":{"name":"ace", "email":"ace@sample","content":"nice"}}}) > db.blog.find() { "_id" : ObjectId("4f636a2b3c82ae09f9857f29"), "comments" : [ { "name" : "joe", "email" : "mongodb@sample", "content" : "good" }, { "name" : "ace", "email" : "ace@sample", "content" : "nice" } ], "content" : "content.....", "owner" : "duuuu", "title" : "mongodb learn" } #批量新增 > db.users.insert({"name":"robin", "address":"chengdu", "age":30}) > db.users.update({"name":"robin"},{"$push":{"emails":{"$each":["[email protected]","[email protected]","[email protected]"]}}}) > db.users.find() { "_id" : ObjectId("4f6421def1c05dbbfa7b6ff7"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]", "[email protected]" ], "name" : "robin" }
- $addToSet
类似saveandupdate没有就更新,有了就不再重复添加。需要注意的是只能对数组类型操作
> db.users.insert({"name":"robin", "address":"chengdu", "age":30}) > db.users.find() { "_id" : ObjectId("4f64179ef1c05dbbfa7b6ff5"), "name" : "robin", "address" : "chengdu", "age" : 30 } > db.users.update({"name":"robin"},{"$addToSet":{"age":33}}) Cannot apply $addToSet modifier to non-array #现在修改为数组 > db.users.find() { "_id" : ObjectId("4f641b65f1c05dbbfa7b6ff6"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]" ], "name" : "robin" } > db.users.update({"name":"robin"},{"$push":{"emails":"[email protected]"}}) > db.users.find() { "_id" : ObjectId("4f641b65f1c05dbbfa7b6ff6"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]" ], "name" : "robin" } #新增一个数组中不存在的属性 > db.users.update({"name":"robin"},{"$addToSet":{"emails":"[email protected]"}}) > db.users.find() { "_id" : ObjectId("4f641b65f1c05dbbfa7b6ff6"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]", "[email protected]" ], "name" : "robin" } #新增一个存在的属性 > db.users.update({"name":"robin"},{"$addToSet":{"emails":"[email protected]"}}) > db.users.find() { "_id" : ObjectId("4f641b65f1c05dbbfa7b6ff6"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]", "[email protected]" ], "name" : "robin" } #批量新增 > db.users.update({"name":"robin"},{"$addToSet":{"emails":{"$each":["[email protected]","[email protected]","[email protected]"]}}}) > db.users.find() { "_id" : ObjectId("4f641b65f1c05dbbfa7b6ff6"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]", "[email protected]", "[email protected]", "[email protected]" ], "name" : "robin" }
- 从数组删除元素
$pop
{"$pop":{key:1}} 从数组末尾删除
{"$pop":{key:-1}} 从数组头部删除
> db.users.find() { "_id" : ObjectId("4f6421def1c05dbbfa7b6ff7"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]", "[email protected]" ], "name" : "robin" } #从数组末尾删 > db.users.update({"name":"robin"},{"$pop":{"emails":1}}) > db.users.find() { "_id" : ObjectId("4f6421def1c05dbbfa7b6ff7"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]" ], "name" : "robin" } #从数组头部删 > db.users.update({"name":"robin"},{"$pop":{"emails":-1}}) > db.users.find() { "_id" : ObjectId("4f6421def1c05dbbfa7b6ff7"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]" ], "name" : "robin" }
$pull
用于删除指定的元素,如果元素不存在不报错
> db.users.find() { "_id" : ObjectId("4f64244ff1c05dbbfa7b6ff8"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]", "[email protected]" ], "name" : "robin" } > db.users.update({"name":"robin"},{"$pull":{"emails":"[email protected]"}}) > db.users.find() { "_id" : ObjectId("4f64244ff1c05dbbfa7b6ff8"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]" ], "name" : "robin" } > db.users.update({"name":"robin"},{"$pull":{"emails":"[email protected]"}}) > db.users.find() { "_id" : ObjectId("4f64244ff1c05dbbfa7b6ff8"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]" ], "name" : "robin" } #尝试了批量删除,但是这样貌似不管用 > db.users.update({"name":"robin"},{"$pull":{"emails":{"$each":["[email protected]","[email protected]"]}}}) > db.users.find() { "_id" : ObjectId("4f64244ff1c05dbbfa7b6ff8"), "address" : "chengdu", "age" : 30, "emails" : [ "[email protected]", "[email protected]" ], "name" : "robin" }
- 数组定位修改
这里对数组中其中一部分数据进行操作,可通过下标或者定位符$操作
> db.blog.find() { "_id" : ObjectId("4f636a2b3c82ae09f9857f29"), "comments" : [ { "name" : "joe", "email" : "mongodb@sample", "content" : "good" }, { "name" : "ace", "email" : "ace@sample", "content" : "nice" }, { "name" : "sam", "email" : "sam@sample", "content" : "ding" } ], "content" : "content.....", "owner" : "duuuu", "title" : "mongodb learn" } #对数组comments第一条记录增加foo属性。这里下标是从0开始 > db.blog.update({"owner":"duuuu"},{"$set":{"comments.0.foo":"bar"}}) > db.blog.find() { "_id" : ObjectId("4f636a2b3c82ae09f9857f29"), "comments" : [ { "content" : "good", "email" : "mongodb@sample", "foo" : "bar", "name" : "joe" }, { "name" : "ace", "email" : "ace@sample", "content" : "nice" }, { "name" : "sam", "email" : "sam@sample", "content" : "ding" } ], "content" : "content.....", "owner" : "duuuu", "title" : "mongodb learn" } #设置comments中两条name记录一致 > db.blog.update({"owner":"duuuu"},{"$set":{"comments.1.name":"joe"}}) #定位操作符($),只会对匹配的第一条记录做修改 > db.blog.update({"comments.name":"joe"},{"$set":{"comments.$.name":"jim"}}) > db.blog.find() { "_id" : ObjectId("4f636a2b3c82ae09f9857f29"), "comments" : [ { "content" : "good", "email" : "mongodb@sample", "foo" : "bar", "name" : "jim" }, { "name" : "joe", "email" : "ace@sample", "content" : "nice" }, { "name" : "sam", "email" : "sam@sample", "content" : "ding" } ], "content" : "content.....", "owner" : "duuuu", "title" : "mongodb learn" } #采用批量的方式,貌似还是不管用 > db.blog.update({"owner":"duuuu"},{"$set":{"comments.0.name":"joe"}}) > db.blog.update({"comments.name":"joe"},{"$set":{"comments.$.name":"jim"}},false,true) > db.blog.find() { "_id" : ObjectId("4f636a2b3c82ae09f9857f29"), "comments" : [ { "content" : "good", "email" : "mongodb@sample", "foo" : "bar", "name" : "jim" }, { "name" : "joe", "email" : "ace@sample", "content" : "nice" }, { "name" : "sam", "email" : "sam@sample", "content" : "ding" } ], "content" : "content.....", "owner" : "duuuu", "title" : "mongodb learn" }
- upsert
如果没有符合条件的记录,就会以这个条件和更新的document创建一个新的记录,如果有则正常更新。通过将update的第三个参数设为true来调用
> db.users.update({"name":"robinn"},{"$set":{"foo":"bar"}},true) > db.users.find() { "_id" : 1, "age" : 30, "foo" : "bar", "name" : "robin" } { "_id" : 2, "age" : 31, "foo" : "bar", "name" : "robin" } { "_id" : 3, "age" : 32, "foo" : "bar", "name" : "robin" } { "_id" : ObjectId("4f6459f52ba49049835032c5"), "foo" : "bar", "name" : "robinn" }
- 更新多个document
在update中,如果有多个匹配的更新结果,默认只会更新第一个,在update中的第四个参数设置true就会对匹配的结果同时更新
> db.users.find({"name":"robin"}) { "_id" : 1, "name" : "robin", "age" : 30 } { "_id" : 2, "name" : "robin", "age" : 31 } { "_id" : 3, "name" : "robin", "age" : 32 } #只会对匹配条件的第一条记录更新 > db.users.update({"name":"robin"},{"$set":{"foo":"bar"}}) > db.users.find({"name":"robin"}) { "_id" : 1, "age" : 30, "foo" : "bar", "name" : "robin" } { "_id" : 2, "name" : "robin", "age" : 31 } { "_id" : 3, "name" : "robin", "age" : 32 } #将第四个参数设置true,此时将会更新所有查找到的记录 > db.users.update({"name":"robin"},{"$set":{"foo":"bar"}},false,true) > db.users.find({"name":"robin"}) { "_id" : 1, "age" : 30, "foo" : "bar", "name" : "robin" } { "_id" : 2, "age" : 31, "foo" : "bar", "name" : "robin" } { "_id" : 3, "age" : 32, "foo" : "bar", "name" : "robin" }
关于修改器的速度,保持一个原则:如果修改操作不需要修改document的大小,那么非常快,否则性能会有所下降
如$inc只是对document的值修改那么将是快速的,而$set如果是对document新增了属性那么性能会有所下降,如果只是改变某个值也会很快。而数组修改器一般改变了document的大小,故性能会有下降