mongodb: update

如此明媚春光,正是打望好时节,恰周末楼下周边溜达,热,遂归。来折腾我的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用来指定一个键的值,如果不存在就创建

扫描二维码关注公众号,回复: 1404378 查看本文章
> 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的大小,故性能会有下降

猜你喜欢

转载自mj4d.iteye.com/blog/1456545