您的位置:首页 > 数据库 > Mongodb

(4)详解MongoDB的创建、更新、删除文档

2012-07-22 22:03 459 查看
1.插入

1.1命令:insert

1.2举例:


>db.blog.insert({"author":"tian","title":"myfirstmongodbblog"})


查询结果:


>db.blog.find()
{"_id":ObjectId("500bb4b44daafbf976598437"),"author":"tian","title":"my
firstmongodbblog"}


1.3说明:

1)当我们要插入的集合(这里是blog)不存在时,mongodb会在第一次插入式自动创建一个;

2)插入的每一条文档,除了我们制定的键(这里有2个键,author和title),还会自动增加一个_id键,相当于关系型数据库的主键,如果我们没有指定的话。

该键对于一个集合必须是唯一的,它可以使任意类型,默认是ObjectId对象。

由于mongodb一开始设计就是用来作为分布式数据库的,因此没有采用自增长的方式来创建_id键,因为在不同的服务器上同步自增长主键费时又费力。

关于ObjectId,更多可以参考:http://www.mongodb.org/display/DOCS/Object+IDs

当然我们也可以自己指定:


>db.blog.insert({"_id":2012,"author":"tian","title":"my2ndmongodbblog"}) >db.blog.find() {"_id":ObjectId("500bb4b44daafbf976598437"),"author":"tian","title":"my firstmongodbblog"} {"_id":2012,"author":"tian","title":"my2ndmongodbblog"}

1.4插入原理:
当我们将数据插入到mongodb数据库时,数据会被转换成BSON的形式(BSON是mongodb存储数据的形式,类似JSON的,是轻量的二进制格式, 能将mongodb的所有文档表示为字节字符串,数据库能理解BSON,存在磁盘上的文档也是BSON格式,更多请参考:http://www.bsonspec.org/), 然后存入数据库。
在这个阶段,mongodb只检查2件事:
1)是否包含_id键;
2)文档是否超过16M,注意,这里的大小是转成BSON格式以后的大小,可以通过Object.bsonsize(your-object)查看大小;(以mongodb1.8为准)
只要这两点满足,就会将文档原本的存入到数据库
这样做有好处也有副作用,副作用就是可以插入无效的数据,好处就是可以使数据库更安全,远离注入式攻击,因为插入不执行代码。


2.删除

2.1命令:remove


2.2举例:


>db.blog.remove({"title":"myfirstmongodbblog"})


>db.blog.remove()

2.3说明:
1)在上面的2个例子中,第一个例子的remove接受一个参数,用于限定要删除的文档,第二个例子没有指定参数,注意,这种操作是很危险的,因为它将删除整个集合里的文档,但是集合以及索引会被保留,第二个例子等价于db.blog.remove({})

2)删除是永久性的,不能撤销,也不能恢复


3)删除文档的速度相当快,如果要删除整个集合里的文档,可以采用db.drop_collection(your-collection),然后重建集合和索引,该方法速度非常快,唯一的缺点是整个集合都被删除了,包括索引


4)根据_id键来删除文档的效率是最高的


5)考虑一种比较极端,或者高并发可能发生的情况,当你要删除一个集合里的文档时,刚好有另一个进程在update其中的文档,在这种情况下,正被update的文档是不会被删除的,如果这并不是你想要的,可以通过制定参数$atomic参数为true来删除所有满足条件的文档,如:db.blog.remove({"author":"tian",$atomic:true}),当然,这样做也是有副作用的,就是当我们执行remove操作的时候,将阻止其他操作。


3.更新


3.1命令:update


3.2举例:



>varmypost=db.blog.findOne({"_id":ObjectId("500bc4304daafbf976598439")})
>mypost.author="tian.chen"
tian.chen
>mypost
{
"_id":ObjectId("500bc4304daafbf976598439"),
"author":"tian.chen",
"title":"myfirstmongodbblog"
}
>db.blog.update({"_id":ObjectId("500bc4304daafbf976598439")},mypost)
>db.blog.findOne({"_id":ObjectId("500bc4304daafbf976598439")})
{
"_id":ObjectId("500bc4304daafbf976598439"),
"author":"tian.chen",
"title":"myfirstmongodbblog"
}

3.3说明:
1)我们首先通过findOne来获取一个文档,并赋值给mypost,然后,修改mypost的author键,最后再通过db.blog.update更新文档
2)更新时匹配多个文档,更新的时候,由于第二个参数的存在就会产生重复的_id键,就会报错。怎么说呢,举个例子

>db.blog.find()
{"_id":ObjectId("500bc4304daafbf976598439"),"author":"tian.chen","title"
:"myfirstmongodbblog","age":28}
{"_id":2012,"author":"tian.chen","title":"my2ndmongodbblog","age":
6}
>vartianpost=db.blog.findOne({"author":"tian.chen","age":6})
>tianpost
{
"_id":2012,
"author":"tian.chen",
"title":"my2ndmongodbblog",
"age":6
}
>tianpost.age=26
26
>db.blog.update({"author":"tian.chen"},tianpost)
cannotchange_idofadocumentold:{_id:ObjectId('500bc4304daafbf976598439'),
author:"tian.chen",title:"myfirstmongodbblog",age:28.0}new:{_id:201
2.0,author:"tian.chen",title:"my2ndmongodbblog",age:26.0}

在这个例子中,我们的post集合里包含2个文档,我们要将第二个文档的age改成26,首先通过author和age获取一个文档并赋值给tianpost,在这里,tianpost也是具有_id键的,其值为2012,然后,我们将tianpost的age改成26后,然后通过author=tian.chen查找文档,将其update为tianpost,问题就出现在这里,通过author=tian.chen查找文档时,首先找到第一个文档,其_id为ObjectId('500bc4304daafbf976598439'),而tianpost._id=2012,我们知道_id是不能修改的,结果就报错了!

为了避免这种情况,最好确保更新总是指定唯一文档。

3.4使用修改器

更新修改是种特殊的键,用来指定复杂的操作,如调整,增加或删除键,还可能操作数据或内嵌的文档。

假设有这样一个文档:

{

"_id":2012,

"age":26,

"author":"tian.chen",

"pageviews":1,

"title":"my2ndmongodbblog"

}

其中的键pageviews表示该post被阅读的次数,每阅读一次就增加1,这时,我们可以使用$inc修改器

>db.blog.update({"_id":2012},{"$inc":{"pageviews":1}})

3.4.1$set修改器

$set修改器用来指定一个键的值,如果这关键不存在就创建它,这对于修改来说是很方便的,因为我们通常修改的只是及个别的键的值的。

假设我们要修改下面文档的age:

{

"_id":2012,

"age":26,

"author":"tian.chen",

"pageviews":1,

"title":"my2ndmongodbblog"

}

如果我们只是简单的用db.blog.update({"_id":2012},{"age":28}),那么,将会用{"age":28}替换掉整个文档,这个时候,$set修改器就很有用处了:

db.blog.update({"_id":2012},{"$set":{"age":28}})

当然,也可以修改多个:

db.blog.update({"_id":2012},{"$set":{"age":28,"author":"tian"}})

用$set可以修改键的值,如果键不存在就创建它,与之对应的,用$unset可以删除键,如:

db.blog.update({"_id":2012},{"$unset":{"pageviews":1}})

这样,就会将文档中的pageviews键删除掉

3.4.2$inc修改器

正如我们在上面看到的,$inc修改器用来增加键的值.

需要注意的是$inc只能应用于整数、长整数、双精度浮点数,同时$inc的键的值必须为数字,如果要修改其他类型,应使用上面的$set

3.4.3数组修改器$push&$pop

如果指定的键存在,$push就会向已有的数据末尾加入一个元素,如果没有,则会创建一个新的数组

如:

>db.blog.update({"_id":2012},{$push:{"comments":{"name":"jake","content":"nicepost"}}})

查出来的结果为:

>db.blog.find()
{"_id":ObjectId("500bc4304daafbf976598439"),"author":"tian.chen","title"

:"myfirstmongodbblog","age":28}

{"_id":2012,"age":28,"author":"tian","comments":[{"name":"jake",

"content":"nicepost"}],"title":"my2ndmongodbblog"}

有时候,我们可能会希望,如果一个值在数组中不存在,就添加进去,可以用如下方式来实现,即通过$ne来实现:

>db.papers.insert({"title":"mongodbpost","authors":["tian"]})

>db.papers.update({"authors":{"$ne":"harry"}},{$push:{"authors":"harry"}})

{"_id":ObjectId("500c0098886e42d4a1a1bff5"),"authors":["tian","harry"],

"title":"mongodbpost"}

也可用$addToSet来实现,因为$ne并不总是可行:

>db.papers.update({"_id":ObjectId("500c0098886e42d4a1a1bff5")},

...{"$addToSet":{"authors":"jerry"}})

>{"_id":ObjectId("500c0098886e42d4a1a1bff5"),"authors":["tian","harry","

jerry"],"title":"mongodbpost"}

$addToSet还有一个妙处,通过与$each结合,可以插入多个值,当然,如果值已经在数组中,就不会被添加进去:

>db.papers.update({"_id":ObjectId("500c0098886e42d4a1a1bff5")},

...{"$addToSet":

...{"authors":{"$each":["tian","jerry","mike"]}}})

{"_id":ObjectId("500c0098886e42d4a1a1bff5"),"authors":["tian","harry","

jerry","mike"],"title":"mongodbpost"}

"tian","jerry"已经存在,因此没有重复添加,"mike"不存在,被添加进来了。

删除数组的元素可以用$pop或$pull

$pop主要用于删除数组头部或尾部的值{$pop:{key:-1}}和{$pop:{key:1}}

>db.papers.find()

{"_id":ObjectId("500c0098886e42d4a1a1bff5"),"authors":["tian","harry","

jerry","mike"],"title":"mongodbpost"}

>db.papers.update({"_id":ObjectId("500c0098886e42d4a1a1bff5")},

...{$pop:{"authors":1}}

...)

>db.papers.find()

{"_id":ObjectId("500c0098886e42d4a1a1bff5"),"authors":["tian","harry","

jerry"],"title":"mongodbpost"}

>db.papers.update({"_id":ObjectId("500c0098886e42d4a1a1bff5")},

...{$pop:{"authors":-1}})

>db.papers.find()

{"_id":ObjectId("500c0098886e42d4a1a1bff5"),"authors":["harry","jerry"]

,"title":"mongodbpost"}

可以发现{$pop:{key:-1}}删除尾部,而{$pop:{key:1}}删除头部的。

更经常的,我们希望通过值来判断,这时候就可以用$pull,{"$pull":{key:value}}

3.5upsert更新

upsert是一种特殊的更新,要是没有符合更新条件的文档,就会以这个条件和文档为基础创建一份新的文档。如果有匹配的文档,则正常更新。

假设我们有一个集合analytics,用来记录每个url的访问次数,每访问一次就给pageviews键加1,正常情况,我们需要判断当前访问的url有没有存在,如果没有,则添加,有则更新。

采用upsert,我们可以有更优雅的写法:

db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":1}},true)

在这里,我们通过给update传递第三个参数表示upsert

3.6save函数

save跟upsert有点类似,也是不存在时插入,存在时更新。不同的是save只有一个参数。看下面的例子:

>varx=db.blog.findOne({"_id":2012})

>x.age=99

99

>db.blog.save(x)

>db.blog.find({"_id":2012})

{"_id":2012,"age":99,"author":"tian","comments":[{"name":

"jake","content":"nicepost"},{"name":"tina",

"content":"nottoobad"}],"title":"my2ndmongodbblog"}

3.7更新多个文档

在前面的例子中,我们都是只更新一个文档,mongodb目前也是默认只更新一个文档。我们可以通过对update指定第四个参数,来更新多个文档





在上面的例子中,我们对比了没传第四个参数和传第四个参数进行更新的区别,传第四个参数后,符合条件的都会更新。

更新完成后,可以通过db.runCommand({getLastError:1})来获取更新了多少文档。

参考:MongoDB权威指南
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: