`
eksliang
  • 浏览: 592327 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

MongoDB更新文档 [四]

阅读更多

MongoDB更新文档

转载请出自出处:http://eksliang.iteye.com/blog/2174104

MongoDB对文档的CURD,前面的博客简单介绍了,但是对文档更新篇幅比较大,所以这里单独拿出来。

语法结构如下:

db.collection.update( criteria, objNew, upsert, multi)

参数含义

参数    含义
criteria update的查询条件,类似sql update查询内where后面的
objNew update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的修改列
upsert 这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi mongodb默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。

 

 

一、文档替换

1、最简单的更新就是用一个新文档完全替换匹配文档。

参考实例

 

> user=db.user.findOne()
{
        "_id" : ObjectId("54ae6fb5b94cf1b60f10570f"),
        "name" : "ickes",
        "pwd" : "xl1",
        "sal" : 1
}
> user.sal=1200                      --将该文档的sal改为1200
1200
> db.user.update({"pwd":"xl1"},user) --完全用新的文档替换集合中pwd=xl的文档
> db.user.findOne()                  --在次查看,替换成功
{
        "_id" : ObjectId("54ae6fb5b94cf1b60f10570f"),
        "name" : "ickes",
        "pwd" : "xl1",
        "sal" : 1200
}
       温馨提示:当查询条件匹配了多个文档,然后更新时由于第二个参数的存在就产生的重复“_id”的值。数据库就会抛出错误。

 

二、使用更新修改器

      通常文档只会有一部分需要更新。可以使用“更新修改器”指定对文档中的某些字段进行更新。更新修改器是特殊的键,用来指定复杂的更新操作,比如修改、添加、删除键,还可以操作数组和内嵌文档。

 1)$inc修改器

       这个修改器是用来计数增加的(如果键不存在会在文档中增加键),例如有一个网站,当有人访问页面时,就计数加一,来做统计

    参考实例

 

> db.iteye.findOne()
{
        "_id" : ObjectId("54af318953b409e1c2efa8d8"),
        "title" : "iteye",
        "count" : 1   --该值本来为1
}
> db.iteye.update({"title":"iteye"},{"$inc":{"count":1}}) --计数修改加1,如果是2,就会加2
> db.iteye.find()     --再次查看
{ "_id" : ObjectId("54af318953b409e1c2efa8d8"), "title" : "iteye", "count" : 2 } --修改成功
 

 

2)$set、$unset修改器

 “$set”修改器用来指定一个字段的值。如果这个字段不存在,则创建他。$unset就是将文档中的某个键完全删除

参考实例

 

> db.user.find()
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xialiang" }
> db.user.update({"name":"xialiang"},{"$set":{"name":"xl","title":"MongoDB"}})
--用set修改器修改第一条数据,name本来就存在,那么修改,而title在原文档中本来不存在,自动添加
> db.user.find() --查看修改结果,发现跟理论一样
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "title" : "MongoD
B" } 
 “$set”修改器修改嵌套文档
    参考实例
> db.iteye.find() --查看iteye集合,里面有一个blog的内嵌文档
{ "_id" : ObjectId("54af318953b409e1c2efa8d8"), "title" : "iteye", "count" : 4,
"blog" : { "title" : "eksliang.iteye.com", "name" : "ickes" } }
> db.iteye.update({"blog.name":"ickes"},{"$set":{"blog.name":"xl"}}) --用$set修改内嵌文档
> db.iteye.find() --查看当前修改,很明显修改成功
{ "_id" : ObjectId("54af318953b409e1c2efa8d8"), "title" : "iteye", "count" : 4,
"blog" : { "title" : "eksliang.iteye.com", "name" : "xl" } }
 “$unset”删除文档的键
参考实例
> db.user.find({"name":"xl"}) --查询name=xl的文档
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "title" : "MongoD
B" }
> db.user.update({"name":"xl"},{"$unset":{"title":1}}) --删除title这个键(这里删除键的值,官网说为任意数字,我测试时,任何值都是没有任何问题的)
> db.user.find({"name":"xl"}) --再次查看,发现键删除成功
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl" }
 
 三、数组修改器

 1)、"$push"修改器

      如果数组已经存在,“$push”会向已有的数组末尾加入一个元素,要是没有就创建一个新的数组。

      参考实例

> db.user.find({"name":"xl"})--先查看name=xl的文档
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "count" : 1 }
> db.user.update({"name":"xl"},{"$push":{"arrys":"aa"}}) --向arrays数组末尾添加一个元素
> db.user.update({"name":"xl"},{"$push":{"arrys":"bb"}}) --在添加一个
> db.user.find({"name":"xl"})--再次查看,果真加进去了,而且arrays这个键本来是不存在,现在有了
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "count" : 1, "arr
ys" : [ "aa", "bb" ] }

2)、$each子操作符 

       单独使用“$push”修改器,每次执行update,都只能加一个元素,怎么添加一次向数组中添加多个元素,使用子操作符$each就可以轻松搞定

> db.user.find({"name":"xl"})
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "count" : 1, "arr
ys" : [ "aa", "bb" ] } --更新之前,数组中只有两个元素
> db.user.update({"name":"xl"},{"$push":{"arrys":{"$each":["cc","dd","ee"]}}})
--使用$eash子操作符,一次向数组后面添加三个元素
> db.user.find({"name":"xl"}) --再次查看,果真不负众望
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "count" : 1, "arr
ys" : [ "aa", "bb", "cc", "dd", "ee" ] }

 3)$slice设定数组的最大长度

       如果希望数组的最大长度是固定的,那么可以将“$slice”和“$push”组合在一起使用,这样就可以保证数组不会超出设定的最大长度,这实际上就得到了一个最多包涵N个元素的数组

参考实例

> db.user.find({"name":"xl"})
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "count" : 1, "arr
ys" : [ "aa", "bb", "cc", "dd", "ee" ] } --数组中本来就有5个元素
> db.user.update({"name":"xl"},
... {"$push":{"arrys":{
... "$each":["ff","gg","hh"],--在添加3个
... "$slice":-6}}})          --限制数组的最大长度为6,该值不能为正,取其绝对值
> db.user.find({"name":"xl"})
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "count" : 1, "arr
ys" : [ "cc", "dd", "ee", "ff", "gg", "hh" ] } --本来应该是8个的,现在只有6个

 其实上面这个例子会限制数组只包涵最后加了的6个元素,也就是说,把新元素加入数组后,最后的6个元素会得以保留,需要注意的是$slice必须为负数。

4、$sort,添加元素后,对数组进行排序

参考实例

> db.user.find({"name":"xl"})
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "count" : 1, "arr
ys" : [ "cc", "dd", "ee", "ff", "gg", "hh" ] } --本来是c~h
> db.user.update({"name":"xl"},
... {"$push":{"arrys":{
... "$each":["zz","xx","aa"],                 --无序的添加三个
... "$slice":-6,                              --数组中最多存放6个元素
... "$sort":-1}}})                            --小于0降序,大于0升序
> db.user.find({"name":"xl"}) --查看结果,果然是最后六个元素的降序
{ "_id" : ObjectId("54ae6fb5b94cf1b60f105710"), "name" : "xl", "count" : 1, "arr
ys" : [ "gg", "ff", "ee", "dd", "cc", "aa" ] }

 

温馨提示:必须要注意的是不能将$slice或者$sort与$push配合使用,$slice与$sort的使用必须带上$each

 

四、将数组作为数据集使用(MongoDB的数组是允许出现重复元素的)

       有时候我们想把数组当做数据集使用,从而保证数组内的元素不能重复。例如我的用户文档中emails用来保存用户的邮箱地址,只有当添加进来的邮箱地址不存在,才添加进来。

$addToSet修改器就是做这件事情的

参考实例

> db.user.find({"name":"cjc"})
{ "_id" : ObjectId("54af71b253b409e1c2efa8da"), "name" : "cjc", "emails" : [ "cj
c@163.com" ] } --emails数组中目前只有一个元素
> db.user.update({"name":"cjc"},   --添加一个eksliang@163.com的邮件地址
... {"$addToSet":{
... "emails":"eksliang@163.com"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.update({"name":"cjc"}, {"$addToSet":{ "emails":"eksliang@163.com"}}) --再添加一次
> db.user.find({"name":"cjc"}) --再次查看发现,其实只添加了一个
{ "_id" : ObjectId("54af71b253b409e1c2efa8da"), "name" : "cjc", "emails" : [ "cj
c@163.com", "eksliang@163.com" ] }

 添加新的邮件地址时,使用$addToSet修改器,可以避免插入重复地址

参考实例二:将$addToSet和$each组合起来,可以添加多个不同的值

> db.user.find({"name":"cjc"})
{ "_id" : ObjectId("54af71b253b409e1c2efa8da"), "name" : "cjc", "emails" : [ "cj
c@163.com", "eksliang@163.com" ] } --原本该数组里面有两个元素
> db.user.update({"name":"cjc"},
... {"$addToSet":{
... "emails":{
... "$each":["eksliang@163.com","ickes@163.com"]} --使用$each批量添加两个
... }})
> db.user.find({"name":"cjc"})--再次查看,发现重复邮件地址eksliang@163.com没有添加进来
{ "_id" : ObjectId("54af71b253b409e1c2efa8da"), "name" : "cjc", "emails" : [ "cj
c@163.com", "eksliang@163.com", "ickes@163.com" ] }

 

5.从文档的数组中删除元素($pop或者$pull)

        有几个从数组中删除元素的方法。若是把数组看出队列或者栈,可以使用“$pop”,这个修改器可以从数组的任何一端删除元素。{"$pop":{"key":1}}从数组末尾删除一个元素,{"$pop":{"key":-1}}则从头部删除。

参考实例一:

> db.user.find() --查看当前集list数组里面有四个元素;
{ "_id" : ObjectId("54af77a953b409e1c2efa8db"), "list" : [ "aa", "bb", "cc", "dd
" ] }
> db.user.update({},{"$pop":{"list":-1}}) --小于0,从前面删除一个元素;
> db.user.find() --查看,发现删除“aa”元素删除了;
{ "_id" : ObjectId("54af77a953b409e1c2efa8db"), "list" : [ "bb", "cc", "dd" ] }
> db.user.update({},{"$pop":{"list":1}})  --大于0,从后面删除一个元素;
> db.user.find() --查看,发现“dd”元素删除了;
{ "_id" : ObjectId("54af77a953b409e1c2efa8db"), "list" : [ "bb", "cc" ] }

有时需要基于特定条件删除元素,而不仅仅是依据元素位置,这时可以使用"$pull"

参考实例二:

> db.user.find() --查看当前数组中有4个元素,两个元素相同;
{ "_id" : ObjectId("54af7a6d53b409e1c2efa8de"), "list" : [ "aa", "bb", "bb", "dd
" ] }
> db.user.update({},{"$pull":{"list":"bb"}}) --删除list数组中等于"bb"的元素;
> db.user.find() --再次查看,删除成功!
{ "_id" : ObjectId("54af7a6d53b409e1c2efa8de"), "list" : [ "aa", "dd" ] }

 从上面实例可以看出"$pull"修改器可以将数组中所有匹配的元素删除

 

 六、save()函数

        save()函数,如果文档不存在,他会自动创建文档,如果文档不存在他会创建新的文档

看下这个函数的源码如下:

function ( obj , opts ){
    if ( obj == null )
        throw "can't save a null";

    if ( typeof( obj ) == "number" || typeof( obj) == "string" )
        throw "can't save a number or string"

    if ( typeof( obj._id ) == "undefined" ){
        obj._id = new ObjectId();
        return this.insert( obj , opts );
    }
    else {
        return this.update( { _id : obj._id } , obj , Object.merge({ upsert:true
 }, opts));
    }
}

   可以看到他的逻辑相当简单,如果添加的文档含有"_id",那么他是调用update(obj,obj,true)方法,如果添加的文档不含有"_id"那么直接调用insert()完成添加。

 

 
 
 
 
 

 

        

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics