本文将讨论关于文档中keyvalue为数组的情况如何修改数组。
首先,创建一个c4集合,集合中的文档包含一个arrint字段,值是一个整数数组;一个arrjson字段,值是一个Json对象数组。
> for(i=0;i<5;i++) 2015-03-12T22:06:52.051+0800 SyntaxError: Unexpected end of input > for(i=0;i<5;i++){ ... db.c4.insert({name:"row"+i,arrint:[i+1,i+2,i+3],arrjson:[{name:"j"+i,age:20+i}]})} WriteResult({ "nInserted" : 1 }) > db.c4.find() { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } { "_id" : ObjectId("55019e3555c37c4b941feb4c"), "name" : "row1", "arrint" : [ 2, 3, 4 ], "arrjson" : [ { "name" : "j1", "age" : 21 } ] } { "_id" : ObjectId("55019e3555c37c4b941feb4d"), "name" : "row2", "arrint" : [ 3, 4, 5 ], "arrjson" : [ { "name" : "j2", "age" : 22 } ] } { "_id" : ObjectId("55019e3555c37c4b941feb4e"), "name" : "row3", "arrint" : [ 4, 5, 6 ], "arrjson" : [ { "name" : "j3", "age" : 23 } ] } { "_id" : ObjectId("55019e3555c37c4b941feb4f"), "name" : "row4", "arrint" : [ 5, 6, 7 ], "arrjson" : [ { "name" : "j4", "age" : 24 } ] } >
这里先对整数数组的进行讨论。
要为数组中增加一个整数元素,可以用$push方法。
取出一个数,可以用$pop,将数组字段设置为1则为最后一个元素,-1则为第一个元素。
这里都是栈的形式,都是从数组末尾插入、取出,先进后出。
$push功能:
如果 filed 是一个已经存在的数组,那么把 value 追加给 field;
如果 field 原来不存在,那么新增 field 字段,把 value 的值赋给 field;
如果 field 存在,但是不是一个数组,将会出错;
$push一次只能压入一个值,如果你强行给其多个数,如[11,12]。那么MongoDB会将[11,12]认为是一个独立完整的元素,将[11,12]作为下一个元素整个插入到数组中。
> db.c4.update({name:"row0"},{$push:{arrint:10}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3, 10 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } > > db.c4.update({name:"row0"},{$push:{arrint:[11,12]}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3, 10, [ 11, 12 ] ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } > > db.c4.update({name:"row0"},{$pop:{arrint:1}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3, 10 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } > db.c4.update({name:"row0"},{$pop:{arrint:1}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } >
如果想压入多个数,需要用到$pushAll:[ ],这里的中括号其实是一个操作符,用来逐一操作多个数。
> db.c4.update({name:"row0"},{$pushAll:{arrint:[13,14]}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3, 13, 14 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } >
如果你像集合那样,希望加入的元素不要有重复,那么请用$addToSet。
功能:
如果 filed 是一个已经存在的数组,并且 value 不在其中,那么把 value 加入到数组;
如果 filed 不存在,那么把 value 当成一个数组形式赋给 field;
如果 field 是一个已经存在的非数组类型,那么将会报错;
> db.c4.update({name:"row0"},{$addToSet:{arrint:14}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 }) > db.c4.update({name:"row0"},{$addToSet:{arrint:14}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 }) > db.c4.update({name:"row0"},{$addToSet:{arrint:15}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3, 13, 14, 15 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } >
相同地,如果要$addToSet多个值也是需要另辟蹊径的。需要与$each配合使用。
> db.c4.update({name:"row0"},{$addToSet:{arrint:{$each:[15,16]}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3, 13, 14, 15, 16 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } >
$pull
语法:
{ $pull : { field : _value } }
功能:
如果 field 是一个数组,那么删除符合_value 检索条件的记录;
如果 field 是一个已经存在的非数组,那么会报错;
$pullAll
语法:
{ $pullAll : { field : value_array } }
功能:
同$push 类似,只是 value 的数据类型是一个数组
> db.c4.update({name:"row0"},{$pull:{arrint:16}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3, 13, 14, 15 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } > db.c4.update({name:"row0"},{$pull:{arrint:{$gte:15}}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3, 13, 14 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } > > db.c4.update({name:"row0"},{$pullAll:{arrint:[13,14]}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrint" : [ 1, 2, 3 ], "arrjson" : [ { "name" : "j0", "age" : 20 } ] } >
$rename
语法:
{ $rename : { old_field_name : new_field_name }
功能:
重命名指定的字段名称,从 1.7.2 版本后开始支持
> db.c4.update({name:"row0"},{$rename:{arrint:"arraryInt"}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrjson" : [ { "name" : "j0", "age" : 20 } ], "arraryInt" : [ 1, 2, 3 ] } >
下面我们进入本文的一个难点,对字段为Json对象数组的修改。
我们先对row0的文档的arrjson字段再添加几个json对象。
> db.c4.update({name:"row0"},{$pushAll:{arrjson:[{name:'j001',age:20},{name:'j0',age:30}]}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrjson" : [ { "name" : "j0", "age" : 20 }, { "name" : "j001", "age" : 20 }, { "name" : "j0", "age" : 30 } ], "arraryInt" : [ 1, 2, 3 ] } >
现在要将row0文档的arrjson字段数组中第一个name为“j0”的对象的age改为25。
> db.c4.update({name:"row0","arrjson.name":"j0"},{$set:{"arrjson.$.age":25}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.c4.find({name:"row0"}) { "_id" : ObjectId("55019e3555c37c4b941feb4b"), "name" : "row0", "arrjson" : [ { "name" : "j0", "age" : 25 }, { "name" : "j001", "age" : 20 }, { "name" : "j0", "age" : 30 } ], "arraryInt" : [ 1, 2, 3 ] } >
特殊操作符:$
$操作符代表查询记录中第一个匹配条件的记录项。
上例中,首先第一个{ }是筛选条件,其中"arrjson.name"选择出arrjson数组中所有name字段为'j0'的json对象。后一个{ }是修改方法,是再前面筛选出来的文档中进行修改,如果用$set:{"arrjson.age":25},无法确定那个子对象是刚才找到的name为'j0'的子对象,所以,这里需要用到$,表示刚才符合第一个匹配条件的那个对象下的age。