文章目录
- 一、什么修改器:
- 二、修改器可分类两大类:
- 字段修改器:
- 数组修改器:
- 三、字段修改器
- 3.1、`$set` 修改某个键值
- 3.2、`$set`用来修改内嵌文档
- 3.3、`$unset` 将键删除
- 3.4、`$inc` 对数字增加或减少
- 四、数组修改器
- 4.1 ` $push` 向数组末尾添加一个元素
- 4.2、`$addToSet` 向数据中添加数据,并去重
- 4.3、` $each` 一次添加多个不同的值
- 4.4、`$pop` 从数组的头部或尾部删除一个元素
- 4.5、`$pull` 删除数组中所有匹配的元素
- 4.6、数组的定位修改器 `$`
- 4.6.1、通过下标位置:
- 4.6.2、定位操作符 `$` :
在mongodb中,通常文档只会有一部分数据要更新。例如要把"foo"的值修改为"bar",常见的错误做法如下:
db.coll.update(criteria,{"foo":"bar"})
这个语句是不对的。
会把整个文档被替换为{"foo":"bar"}
,一定要使用以$
开头的修改器来修改键/值对。
一、什么修改器:
修改器是种特殊的键,用来指定复杂的更新操作,比如调整、增加、或者删除键,还可以操作数组和内嵌文档。
可以做到只更新文档的一部分键值,而且更新极为高效。
二、修改器可分类两大类:
字段修改器:
$set
、$unset
、$inc
、$rename
数组修改器:
$push
、$pullAll
、$addToSet
、$each
、$pop
、$pull
、$
三、字段修改器
3.1、$set
修改某个键值
$set
修改器用来指定一个键值。如果这个键不存在,则创建他,他对更新模式或者用户定义键来说非常方便。
> db.users.findOne()
{
"_id" : ObjectId("56fe7df8b322e3ff1dabf834"),
"name" : "joe",
"age" : 30,
"sex" : "male",
"location" : "Wisconsin",
"favorite book" : "war and pace"
}
> db.users.update({"name":"joe"},{"$set":{"favorite book":["cat's cardle","foundation trilogy","ender's game"]}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
"_id" : ObjectId("56fe7df8b322e3ff1dabf834"),
"name" : "joe",
"age" : 30,
"sex" : "male",
"location" : "Wisconsin",
"favorite book" : [
"cat's cardle",
"foundation trilogy",
"ender's game"
]
}
3.2、$set
用来修改内嵌文档
> db.blog.insert({"title":"a blog post","author":{"name":"joe","email":"joe@example.com"}})
WriteResult({ "nInserted" : 1 })
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"author" : {
"name" : "joe",
"email" : "joe@example.com"
}
}
> db.blog.update({"author.name":"joe"},{"$set":{"author.name":"joe schmoe"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"author" : {
"name" : "joe schmoe",
"email" : "joe@example.com"
}
}
> db.blog.update({"title":"a blog post"},{"$set":{"author.name":"joe schmoe op"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"author" : {
"name" : "joe schmoe op",
"email" : "joe@example.com"
}
}
>
3.3、$unset
将键删除
$unset
用于将键和对应的数据全部删除
格式:{$unset:{filed:1}}
:
field 后面对应的可以填0,也可以填1或其他数值,但效果都是将该键从这条数据中删除。
> db.users.findOne()
{
"_id" : ObjectId("56fe7df8b322e3ff1dabf834"),
"name" : "joe",
"age" : 30,
"sex" : "male",
"location" : "Wisconsin",
"favorite book" : [
"cat's cardle",
"foundation trilogy",
"ender's game"
]
}
> db.users.update({"name":"joe"},{"$unset":{"favorite book":1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
"_id" : ObjectId("56fe7df8b322e3ff1dabf834"),
"name" : "joe",
"age" : 30,
"sex" : "male",
"location" : "Wisconsin"
}
3.4、$inc
对数字增加或减少
$inc
其用来增加或减少已有的键的键值,或者在键不存在的时候创建一个键。
格式:{$inc:{filed:value}}
,为指定的键对应的数值进行加减
> db.games.insert({"game":"pinball","user":"joe"})
WriteResult({ "nInserted" : 1 })
> db.games.findOne()
{
"_id" : ObjectId("5770a1394f533aa7535d46d4"),
"game" : "pinball",
"user" : "joe"
}
> db.games.update({"game":"pinball","user":"joe"},{"$inc":{"score":50}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.games.findOne()
{
"_id" : ObjectId("5770a1394f533aa7535d46d4"),
"game" : "pinball",
"user" : "joe",
"score" : 50
}
为"score"键增加 50 再减少 20
> db.games.update({"game":"pinball","user":"joe"},{"$inc":{"score":50}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.games.findOne()
{
"_id" : ObjectId("5770a1394f533aa7535d46d4"),
"game" : "pinball",
"user" : "joe",
"score" : 100
}
> db.games.update({"game":"pinball","user":"joe"},{"$inc":{"score":-20}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.games.findOne()
{
"_id" : ObjectId("5770a1394f533aa7535d46d4"),
"game" : "pinball",
"user" : "joe",
"score" : 80
}
以上 $inc
与 $set
的用法类似,就是专门用来增加或减少数字的。$inc
只能用于整数、长整数或双精度浮点数,要是在其他类型的数据上就会导致操作失败,其中包括很多语言会自动转换成数字的类型,例如 null,布尔类型,或数字构成的字符串。$inc
键的值必须为数字,不能使用字符串、数组和其他非数字的值,否则会报错,要修改其他类型,只能使用$set
。
> db.foo.insert({"count":"1"})
WriteResult({ "nInserted" : 1 })
> db.foo.find()
{ "_id" : ObjectId("5770befc4f533aa7535d46d5"), "count" : "1" }
> db.foo.update({},{"$inc":{"count":1}})
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 16837,
"errmsg" : "Cannot apply $inc to a value of non-numeric type. {_id: ObjectId('5770befc4f533aa7535d46d5')} has the field 'count' of non-numeric type String"
}
})
> db.foo.update({},{$set:{count:2}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.foo.find()
{ "_id" : ObjectId("5770befc4f533aa7535d46d5"), "count" : 2 }
>
四、数组修改器
数组修改器,顾名思义它只可以用于操作数组,只能用在值为数组的键上。
4.1 $push
向数组末尾添加一个元素
$push
向数组末尾添加一个元素。
如果没有数组,就会创建一个新的数组,并添加数据。
不过滤重复的数据,数据可以重复。
格式:{$push:{filed:value}}
中的field应为数组类型的,
如果field不是数组类型的,就会出错,
如果filed不存在,则创建该数组类型并插入数据。
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"author" : {
"name" : "joe schmoe op",
"email" : "joe@example.com"
}
}
> db.blog.update(
{ "title" : "a blog post" }
,{ "$unset" : { "author":1 } }
)
## 删除了key是author的所有数据
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{ "_id" : ObjectId("57709da84f533aa7535d46d3"), "title" : "a blog post" } ## 删除了key是author的所有数据
> db.blog.update(
{ "title" : "a blog post" }
,{ "$push" :
{ "comments" : {"name":"joe","email":"joe@example.com","content":"nice post"} }
}
) ## 添加key是comments的数组类型的数据
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post"
}
]
}
为blog集合"a blog post"文档再增加一条评论:
> db.blog.update(
{"title":"a blog post"}
,{
"$push" : { "comments" : { "name":"bob","email":"bob@example.com","content":"good post"} }
}
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post"
},
{
"name" : "bob",
"email" : "bob@example.com",
"content" : "good post"
}
]
}
4.2、$addToSet
向数据中添加数据,并去重
addToSet 可以理解为 add to Set ,添加元素到set集合中,set集合可以去重。所以,$addToSet
还有去重功能。
格式:{$addToSet:{filed:value}}
向 field 目标 数组 中添加数据,
如果目标数组中已存在value,则什么都不操作,(避免重复) 。
如不存在,则添加进去。
实现的功能与 $ne
修改器相同,且比 $ne
更为方便。
$addToSet
不会对集合中已有的数据进行去重操作,而只对要添加的元素,在添加前先要查询value值是否存在。
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com"
]
}
> db.users.update(
{ "_id" : ObjectId("5770ca42e90c1adc80040a08" ) }
, { $addToSet : {"emails":"joe@gmail.com" }
})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
--原文档里已有"joe@gmail.com",修改完也没有产生重复值
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com"
]
}
> db.users.update(
{"_id" : ObjectId("5770ca42e90c1adc80040a08") }
,{ $addToSet : { "emails":"joe@163.com" }
})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com",
"joe@163.com"
]
}
4.3、$each
一次添加多个不同的值
$each
数组修改器要和 $addToSet
修改结合起来用,可以一次添加多个不同的值。
例如下面的例子中,我们一次添加多个 email 值, 如下:
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com",
"joe@163.com"
]
}
> db.users.update(
{"_id":ObjectId("5770ca42e90c1adc80040a08")}
,{ $addToSet:{ $each:["joe@example.com","joe@python.com","joe@php.com"] }
})
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 52,
"errmsg" : "The dollar ($) prefixed field '$each' in '$each' is not valid for storage."
}
})
## 上面报的是语法错误,必须指定key值,比如emails,来储存数据。
> db.users.update(
{ "_id" : ObjectId("5770ca42e90c1adc80040a08") }
,{ $addToSet:{ "emails" : { $each:["joe@example.com","joe@python.com","joe@php.com"] } }
})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com",
"joe@163.com",
"joe@python.com",
"joe@php.com"
]
}
>
4.4、$pop
从数组的头部或尾部删除一个元素
$pop
通过位置(下标)删除数组元素。只能从数组的头部或尾部删除一个元素 。
格式:{$pop:{filed:value}}
,field 为数组类型,value 为 1 或者 -1 ,
value 为 1 时,删除指定数组的最后一个值;
value 为 -1 删除指定数组第一个值。
{$pop:{key:1}}
从数组末尾删除一个元素{$pop:{key:-1}}
从数组头部删除一个元素
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com",
"joe@163.com",
"joe@python.com",
"joe@php.com"
]
}
> db.users.update( { "name":"joe" } , { $pop:{"emails":1} } )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@example.com",
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com",
"joe@163.com",
"joe@python.com"
]
}
> db.users.update( { "name" : "joe" } , { $pop : { "emails" : -1 } } )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com",
"joe@163.com",
"joe@python.com"
]
}
有时我们需要基于特定条件来删除元素,而不仅仅依据位置,就可以使用 $pull
修改器
4.5、$pull
删除数组中所有匹配的元素
$pull
删除数组元素,将所有匹配的元素删除。
和 $pop
修改类似,但是比 $pop
强大的多。
例如我们想删除 emails 数组中的 joe@163.com
和 joe@itpub.com
两个元素:
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com",
"joe@163.com",
"joe@python.com"
]
}
> db.users.update(
{"name":"joe"}
, { $pull : { "emails" : [ "joe@163.com","joe@itpub.com"] }
})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 }) --好像不能一次删除多个,没有起作用
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@gmail.com",
"joe@yahoo.com",
"joe@itpub.com",
"joe@163.com",
"joe@python.com"
]
}
> db.users.update( {"name" : "joe" } , { $pull : { "emails" : "joe@163.com" } } )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.update( {"name":"joe"} , { $pull : {"emails":"joe@itpub.com"} })
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
"_id" : ObjectId("5770ca42e90c1adc80040a08"),
"name" : "joe",
"emails" : [
"joe@gmail.com",
"joe@yahoo.com",
"joe@python.com"
]
}
4.6、数组的定位修改器 $
若是数组中有多个值,而我们只想对其中一部分进行操作,有两种方法可以实现这种操作。
两种方法操作数组中的值:
- 通过下标位置
- 定位操作符
$
4.6.1、通过下标位置:
数组都是以 0 开头的,可以将下标直接作为键来选择元素。
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post"
},
{
"name" : "bob",
"email" : "bob@example.com",
"content" : "good post"
}
]
}
> db.blog.update(
{"title":"a blog post"}
,{ $set : { "comments.1.name":"livan" } }
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post"
},
{
"name" : "livan",
"email" : "bob@example.com",
"content" : "good post"
}
]
}
> db.blog.update( {"title":"a blog post"} , { $set : { "comments.1.email":"livan@example.com"} } )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post"
},
{
"name" : "livan",
"email" : "livan@example.com",
"content" : "good post"
}
]
}
4.6.2、定位操作符 $
:
在很多情况下,不预先查询文档就不能知道要修改数组的下标,为了克服这种困难,mongodb 提供了定位操作符 $
,
用来定位查询文档已经匹配的元素,并进行更新,定位符只更新第一个匹配的元素。
例如:用户 john 把名字改成了 jim,就可以用定位符来替换评论中的名字:db.blog.update({"comments.author":"john"},{$set:{"comments.$.author:"john"}})
可以理解为{"comments.author":"john"}
查询条件定位到第一个元素,就执行{ $se t: {"comments.$.author:"john"} }
,$
定位符就表示找到的第一个元素
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post"
},
{
"name" : "livan",
"email" : "livan@example.com",
"content" : "good post"
}
]
}
> db.blog.update({"comments.name":"livan"},{$set:{"comments.$.email":"bob@example.com"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.update({"comments.name":"livan"},{$set:{"comments.$.name":"bob"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
"_id" : ObjectId("57709da84f533aa7535d46d3"),
"title" : "a blog post",
"comments" : [
{
"name" : "joe",
"email" : "joe@example.com",
"content" : "nice post"
},
{
"name" : "bob",
"email" : "bob@example.com",
"content" : "good post"
}
]
}