对于文档的更新除替换外,针对某个或多个文档只需要部分更新可使用原子的更新修改器,能够高效的进行文档更新。更新修改器是中特殊的键,
用来指定复杂的操作,比如增加、删除或者调整键,还可能是操作数组或者内嵌文档。
1.$inc
这个修改器干什么使的呢?看看下面示例的具体操作后的结果即可知道。
示例文档:{"uid":"201203","type":"1",size:10}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
> db.b. insert ({ "uid" : "201203" , "type" : "1" , size :10}) > db.b.find() { "_id" : ObjectId( "5003b6135af21ff428dafbe6" ), "uid" : "201203" , "type" : "1" , "size" : 10 } > db.b. update ({ "uid" : "201203" },{ "$inc" :{ "size" : 1}}) > db.b.find() { "_id" : ObjectId( "5003b6135af21ff428dafbe6" ), "uid" : "201203" , "type" : "1" , "size" : 11 } > db.b. update ({ "uid" : "201203" },{ "$inc" :{ "size" : 2}}) > db.b.find() { "_id" : ObjectId( "5003b6135af21ff428dafbe6" ), "uid" : "201203" , "type" : "1" , "size" : 13 } > db.b. update ({ "uid" : "201203" },{ "$inc" :{ "size" : -1}}) > db.b.find() { "_id" : ObjectId( "5003b6135af21ff428dafbe6" ), "uid" : "201203" , "type" : "1" , "size" : 12 } |
得出结论:修改器$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
(这里有个问题:上篇中说到更新默认只对满足条件的记录集中第一个文档进行更新,那么使用$inc修改器之后,还是一样吗?)
2.$set
用来指定一个键并更新键值,若键不存在并创建。来看看下面的效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
> db.a.findOne({ "uid" : "20120002" , "type" : "3" }) { "_id" : ObjectId( "500216de81b954b6161a7d8f" ), "desc" : "hello world2!" , "num" : 40, "sname" : "jk" , "type" : "3" , "uid" : "20120002" } --size键不存在的场合 > db.a. update ({ "uid" : "20120002" , "type" : "3" },{ "$set" :{ "size" :10}}) > db.a.findOne({ "uid" : "20120002" , "type" : "3" }) { "_id" : ObjectId( "500216de81b954b6161a7d8f" ), "desc" : "hello world2!" , "num" : 40, "size" : 10, "sname" : "jk" , "type" : "3" , "uid" : "20120002" } --sname键存在的场合 > db.a. update ({ "uid" : "20120002" , "type" : "3" },{ "$set" :{ "sname" : "ssk" }}) > db.a.find() { "_id" : ObjectId( "500216de81b954b6161a7d8f" ), "desc" : "hello world2!" , "num" : 40, "size" : 10, "sname" : "ssk" , "type" : "3" , "uid" : "20120002" } { "_id" : ObjectId( "50026affdeb4fa8d154f8572" ), "desc" : "hello world1!" , "num" : 50, "sname" : "jk" , "type" : "1" , "uid" : "20120002" } --可改变键的值类型 > db.a. update ({ "uid" : "20120002" , "type" : "3" },{ "$set" :{ "sname" :[ "Java" , ".net" , "c++" ]}}) > db.a.findOne({ "uid" : "20120002" , "type" : "3" }) { "_id" : ObjectId( "500216de81b954b6161a7d8f" ), "desc" : "hello world2!" , "num" : 40, "size" : 10, "sname" : [ "java" , ".net" , "c++" ], "type" : "3" , "uid" : "20120002" } |
对于内嵌的文档,$set又是如何进行更新的内嵌的文档的呢,请看下面的示例:
示例文档:{"name":"toyota","type":"suv","size":{"height":10,"width":5,"length":15}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
> db.c.findOne({ "name" : "toyota" }) { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "type" : "suv" , "size" : { "height" : 10, "width" : 5, "length" : 15 } } > db.c. update ({ "name" : "toyota" },{ "$set" :{ "size.height" :8}}) > db.c.findOne({ "name" : "toyota" }) { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "type" : "suv" , "size" : { "height" : 8, "width" : 5, "length" : 15 } } > db.c. update ({ "name" : "toyota" },{ "$set" :{ "size.width" :7}}) > db.c.findOne({ "name" : "toyota" }) { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "type" : "suv" , "size" : { "height" : 8, "width" : 7, "length" : 15 } } |
可见:对于内嵌文档在使用$set更新时,使用"."连接的方式。
3.$unset
从字面就可以看出其意义,主要是用来删除键。
示例操作效果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
> db.a. update ({ "uid" : "20120002" , "type" : "3" },{ "$unset" :{ "sname" :1}}) > db.a.findOne({ "uid" : "20120002" , "type" : "3" }) { "_id" : ObjectId( "500216de81b954b6161a7d8f" ), "desc" : "hello world2!" , "num" : 40, "size" : 10, "type" : "3" , "uid" : "20120002" } > db.a. update ({ "uid" : "20120002" , "type" : "3" },{ "$unset" :{ "num" :0}}) > db.a.findOne({ "uid" : "20120002" , "type" : "3" }) { "_id" : ObjectId( "500216de81b954b6161a7d8f" ), "desc" : "hello world2!" , "size" : 10, "type" : "3" , "uid" : "20120002" } > db.a. update ({ "uid" : "20120002" , "type" : "3" },{ "$unset" :{ "size" :-1}}) > db.a.findOne({ "uid" : "20120002" , "type" : "3" }) { "_id" : ObjectId( "500216de81b954b6161a7d8f" ), "desc" : "hello world2!" , "type" : "3" , "uid" : "20120002" } > db.a. update ({ "uid" : "20120002" , "type" : "3" },{ "$unset" :{ "desc" : "sssssss" }}) > db.a.findOne({ "uid" : "20120002" , "type" : "3" }) { "_id" : ObjectId( "500216de81b954b6161a7d8f" ), "type" : "3" , "uid" : "20120002" } |
得出结论:使用修改器$unset时,不论对目标键使用1、0、-1或者具体的字符串等都是可以删除该目标键。
4.数组修改器--$push
示例操作效果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
> db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "type" : "suv" , "size" : { "height" : 8, "width" : 7, "length" : 15 } } --先push一个当前文档中不存在的键title > db.c. update ({ "name" : "toyota" },{$push:{ "title" : "t1" }}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" ], "type" : "suv" } --再向title中push一个值 > db.c. update ({ "name" : "toyota" },{$push:{ "title" : "t2" }}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" , "t2" ], "type" : "suv" } --再向title中push一个值 > db.c. update ({ "name" : "toyota" },{$push:{ "title" : "t2" }}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" , "t2" , "t2" ], "type" : "suv" } --再向一个已经存在的键值非数组类型的键push一个值 > db.c. update ({ "name" : "toyota" },{$push:{ "size.height" :10}}) Cannot apply $push/$pushAll modifier to non-array > db.c. update ({ "name" : "toyota" },{$push:{ "name" : "ddddddd" }}) Cannot apply $push/$pushAll modifier to non-array |
得出结论:$push--向文档的某个数组类型的键添加一个数组元素,不过滤重复的数据。添加时键存在,要求键值类型必须是数组;键不存在,则创建数组类型的键。
5.数组修改器--$ne/$addToSet
主要给数组类型键值添加一个元素时,避免在数组中产生重复数据,$ne在有些情况是不通行的。
1
2
3
4
5
6
7
8
|
> db.c. update ({ "title" : {$ne: "t2" }},{$push:{ "title" : "t2" }}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" , "t2" , "t2" ], "type" : "suv" } > db.c. update ({ "name" : "toyota" },{$addToSet:{ "title" : "t2" }}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" , "t2" , "t2" ], "type" : "suv" } |
6.数组修改器--$pop、$pull
$pop从数组的头或者尾删除数组中的元素,示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
{ "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" , "t2" , "t3" , "t4" ], "type" : "suv" } --从数组的尾部删除 1 > db.c. update ({ "name" : "toyota" },{$pop:{ "title" :1}}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" , "t2" , "t3" ], "type" : "suv" } --从数组的头部 -1 > db.c. update ({ "name" : "toyota" },{$pop:{ "title" :-1}}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t2" , "t3" ], "type" : "suv" } --从数组的尾部删除 0 > db.c. update ({ "name" : "toyota" },{$pop:{ "title" :0}}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t2" ], "type" : "suv" } $pull从数组中删除满足条件的元素,示例如下: { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" , "t2" , "t2" , "t3" ], "type" : "suv" } > db.c. update ({ "name" : "toyota" },{$pull:{ "title" : "t2" }}) > db.c.find() { "_id" : ObjectId( "5003be465af21ff428dafbe7" ), "name" : "toyota" , "size" : { "height" : 8, "width" : 7, "length" : 15 }, "title" : [ "t1" , "t3" ], "type" : "suv" } |
7.数组的定位修改器
在需要对数组中的值进行操作的时候,可通过位置或者定位操作符("$").数组是0开始的,可以直接将下标作为键来选择元素。
示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
{ "uid" : "001" ,comments:[{ "name" : "t1" , "size" :10},{ "name" : "t2" , "size" :12}]} > db.c.find({ "uid" : "001" }) { "_id" : ObjectId( "5003da405af21ff428dafbe8" ), "uid" : "001" , "comments" : [ { "name" : "t1" , "size" : 10 }, { "name" : "t2" , "size" : 12 } ] } > db.c. update ({ "uid" : "001" },{$inc:{ "comments.0.size" :1}}) > db.c.find({ "uid" : "001" }) { "_id" : ObjectId( "5003da405af21ff428dafbe8" ), "uid" : "001" , "comments" : [ { "name" : "t1" , "size" : 11 }, { "name" : "t2" , "size" : 12 } ] } > db.c. update ({ "comments.name" : "t1" },{$ set :{ "comments.$.size" :1}}) > db.c.find({ "uid" : "001" }) { "_id" : ObjectId( "5003da405af21ff428dafbe8" ), "uid" : "001" , "comments" : [ { "name" : "t1" , "size" : 1 }, { "name" : "t2" , "size" : 12 } ] } --若为多个文档满足条件,则只更新第一个文档。 |
8.upsert
upsert是一种特殊的更新。当没有符合条件的文档,就以这个条件和更新文档为基础创建一个新的文档,如果找到匹配的文档就正常的更新。
使用upsert,既可以避免竞态问题,也可以减少代码量(update的第三个参数就表示这个upsert,参数为true时)
1
2
3
4
5
6
7
8
|
> db.c.remove() > db.c. update ({ "size" :11},{$inc:{ "size" :3}}) > db.c.find() > db.c. update ({ "size" :11},{$inc:{ "size" :3}}, false ) > db.c.find() > db.c. update ({ "size" :11},{$inc:{ "size" :3}}, true ) > db.c.find() { "_id" : ObjectId( "5003ded6c28f67507a6df1de" ), "size" : 14 } |
9.save函数
1.可以在文档不存在的时候插入,存在的时候更新,只有一个参数文档。
2.要是文档含有"_id",会调用upsert。否则,会调用插入。
1
2
3
4
5
6
7
8
9
10
|
> db.a.find() { "_id" : ObjectId( "50026affdeb4fa8d154f8572" ), "desc" : "hello world1!" , "num" : 50, "sname" : "jk" , "type" : "1" , "uid" : "20120002" } > var o = db.a.findOne() > o.num = 55 55 > db.a.save(o) > db.a.find() { "_id" : ObjectId( "50026affdeb4fa8d154f8572" ), "desc" : "hello world1!" , "num" : 55, "sname" : "jk" , "type" : "1" , "uid" : "20120002" } |
原文链接:http://blog.csdn.net/mcpang/article/details/7752736