小雨点点789 发表于 2015-7-8 07:11:56

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

  1. 插入
  
  1.1 命令:insert
  1.2 举例:

  > db.blog.insert({"author":"tian","title":"my first mongodb blog"})

  查询结果:

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

  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":"my 2nd mongodb blog"})
> db.blog.find()
{ "_id" : ObjectId("500bb4b44daafbf976598437"), "author" : "tian", "title" : "my
first mongodb blog" }
{ "_id" : 2012, "author" : "tian", "title" : "my 2nd mongodb blog" }

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)查看大小;(以mongodb 1.8为准)
只要这两点满足,就会将文档原本的存入到数据库
这样做有好处也有副作用,副作用就是可以插入无效的数据,好处就是可以使数据库更安全,远离注入式攻击,因为插入不执行代码。

  
  

2. 删除

  2.1 命令:remove

  2.2 举例:


> db.blog.remove({"title":"my first mongodb blog"})


> 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 举例:


> var mypost = db.blog.findOne({"_id":ObjectId("500bc4304daafbf976598439")})
> mypost.author="tian.chen"
tian.chen
> mypost
{
"_id" : ObjectId("500bc4304daafbf976598439"),
"author" : "tian.chen",
"title" : "my first mongodb blog"
}
> db.blog.update({"_id":ObjectId("500bc4304daafbf976598439")},mypost)
> db.blog.findOne({"_id":ObjectId("500bc4304daafbf976598439")})
{
"_id" : ObjectId("500bc4304daafbf976598439"),
"author" : "tian.chen",
"title" : "my first mongodb blog"
}

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

> db.blog.find()
{ "_id" : ObjectId("500bc4304daafbf976598439"), "author" : "tian.chen", "title"
: "my first mongodb blog", "age" : 28 }
{ "_id" : 2012, "author" : "tian.chen", "title" : "my 2nd mongodb blog", "age" :
6 }
> var tianpost=db.blog.findOne({"author":"tian.chen","age":6})
> tianpost
{
"_id" : 2012,
"author" : "tian.chen",
"title" : "my 2nd mongodb blog",
"age" : 6
}
> tianpost.age=26
26
> db.blog.update({"author":"tian.chen"},tianpost)
cannot change _id of a document old:{ _id: ObjectId('500bc4304daafbf976598439'),
author: "tian.chen", title: "my first mongodb blog", age: 28.0 } new:{ _id: 201
2.0, author: "tian.chen", title: "my 2nd mongodb blog", 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" : "my 2nd mongodb blog"
  }
  其中的键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" : "my 2nd mongodb blog"
  }
  如果我们只是简单的用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":"nice post"}}})
  查出来的结果为:
  > db.blog.find()
{ "_id" : ObjectId("500bc4304daafbf976598439"), "author" : "tian.chen", "title"
: "my first mongodb blog", "age" : 28 }
{ "_id" : 2012, "age" : 28, "author" : "tian", "comments" : [ { "name" : "jake",
"content" : "nice post" } ], "title" : "my 2nd mongodb blog" }
  
  有时候,我们可能会希望,如果一个值在数组中不存在,就添加进去,可以用如下方式来实现,即通过$ne来实现:
  > db.papers.insert({"title":"mongodb post","authors":["tian"]})
  > db.papers.update({"authors":{"$ne":"harry"}},{$push:{"authors":"harry"}})
  { "_id" : ObjectId("500c0098886e42d4a1a1bff5"), "authors" : [ "tian", "harry" ],
"title" : "mongodb post" }
  
  也可用$addToSet来实现,因为$ne并不总是可行:
  > db.papers.update({"_id": ObjectId("500c0098886e42d4a1a1bff5")},
... {"$addToSet":{"authors":"jerry"}})
  >{ "_id" : ObjectId("500c0098886e42d4a1a1bff5"), "authors" : [ "tian", "harry", "
jerry" ], "title" : "mongodb post" }
  
  $addToSet还有一个妙处,通过与$each结合,可以插入多个值,当然,如果值已经在数组中,就不会被添加进去:
  > db.papers.update({"_id": ObjectId("500c0098886e42d4a1a1bff5")},
... {"$addToSet":
... {"authors":{"$each":["tian","jerry","mike"]}}})
  
  { "_id" : ObjectId("500c0098886e42d4a1a1bff5"), "authors" : [ "tian", "harry", "
jerry", "mike" ], "title" : "mongodb post" }
  
  "tian","jerry"已经存在,因此没有重复添加,"mike"不存在,被添加进来了。
  
  删除数组的元素可以用$pop或$pull
  $pop主要用于删除数组头部或尾部的值{$pop:{key:-1}}和{$pop:{key:1}}
  > db.papers.find()
{ "_id" : ObjectId("500c0098886e42d4a1a1bff5"), "authors" : [ "tian", "harry", "
jerry", "mike" ], "title" : "mongodb post" }
> db.papers.update({"_id": ObjectId("500c0098886e42d4a1a1bff5")},
... {$pop:{"authors":1}}
... )
> db.papers.find()
{ "_id" : ObjectId("500c0098886e42d4a1a1bff5"), "authors" : [ "tian", "harry", "
jerry" ], "title" : "mongodb post" }
> db.papers.update({"_id": ObjectId("500c0098886e42d4a1a1bff5")},
... {$pop:{"authors":-1}})
> db.papers.find()
{ "_id" : ObjectId("500c0098886e42d4a1a1bff5"), "authors" : [ "harry", "jerry" ]
, "title" : "mongodb post" }
  
  可以发现{$pop:{key:-1}}删除尾部,而{$pop:{key:1}}删除头部的。
  
  更经常的,我们希望通过值来判断,这时候就可以用$pull,{"$pull":{key:value}}
  
  3.5 upsert更新
  upsert是一种特殊的更新,要是没有符合更新条件的文档,就会以这个条件和文档为基础创建一份新的文档。如果有匹配的文档,则正常更新。
  假设我们有一个集合analytics,用来记录每个url的访问次数,每访问一次就给pageviews键加1,正常情况,我们需要判断当前访问的url有没有存在,如果没有,则添加,有则更新。
  采用upsert,我们可以有更优雅的写法:
  db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":1}},true)
  
  在这里,我们通过给update传递第三个参数表示upsert
  
  3.6 save函数
  save跟upsert有点类似,也是不存在时插入,存在时更新。不同的是save只有一个参数。看下面的例子:
  > var x = 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" : "nice post" },      {       "name" : "tina",
"content" : "not too bad" } ], "title" : "my 2nd mongodb blog" }
  
  3.7 更新多个文档
  在前面的例子中,我们都是只更新一个文档,mongodb目前也是默认只更新一个文档。我们可以通过对update指定第四个参数,来更新多个文档
  

  在上面的例子中,我们对比了没传第四个参数和传第四个参数进行更新的区别,传第四个参数后,符合条件的都会更新。
  更新完成后,可以通过db.runCommand({getLastError:1})来获取更新了多少文档。
  
  参考:MongoDB权威指南
页: [1]
查看完整版本: (4)详解MongoDB的创建、更新、删除文档