MongoDB入门学习(三):MongoDB的增删查改(一)

2014-11-24 10:28:26 · 作者: · 浏览: 0

对于我们这种菜鸟来说,最重要的不是数据库的管理,也不是数据库的性能,更不是数据库的扩展,而是怎么用好这款数据库,也就是一个数据库提供的最核心的功能,增删查改。

因为MongoDB存储数据都是以文档的模式,所以在操作它的数据时,也是以文档为单位的。那么我们实现增删查改也是以文档为基础,不知道文档是什么的同学可以看看上篇介绍的基本概念。

1.插入文档

向MongoDB集合中插入文档的基本方法是insert:

单个插入
> document = {key : value}
> db.collectionName.insert(document)
批量插入
> documents = [{key : value}, {key : value}, {key : value}, ...]
传入数组
> db.collectionName.insert(documents)
for循环
> for(var i = 0; i < documents.length; i++){
...  db.people.insert(documents[i]);
...  }

因为集合是无模式的,集合中的文档可以是各式各样的,所以在插入方面是很随意的,想一次插入很多数据的话可以使用for循环,也可以使用批量插入,传入一个由文档构成的数组。因为使用for循环来实现批量插入会为每次插入建立一个TCP连接,而传入数组实现批量插入只有一次TCP连接,所以在效率上来说,for的效率会比传入数组要低。

还有一种插入的方式save,在shell中可以使用db.collectionName.function不加括号来看方法的实现,可以看出insert和save的区别,看个小例子:

> db.people.find()
{ "_id" : 1, "name" : "mary", "age" : 20 }
> db.people.insert({"_id" : 1, "name" : "amy", "age" : 22})
E11000 duplicate key error index: test.people.$_id_  dup key: { : 1.0 }
> db.people.save({"_id" : 1, "name" : "amy", "age" : 22})
> db.people.find()
{ "_id" : 1, "name" : "amy", "age" : 22 }

本来people集合中已经有一个文档了,如果我们要插入的文档中的主键"_id"在集合中已经存在一样的值则会报错,而save就不会。没有一样的主键时,insert和save一样都执行插入操作,有一样的主键时,insert就报错,save就执行更新操作,用新文档的内容来替换已经原来的内容,和update操作一样,所以mary被替换成了amy。

执行插入操作的时候,驱动程序先将数据转换成BSON的形式,然后再送入数据库,只检验是否包含了"_id"键,文档是否超过4MB(能插入的文档最大为4MB,超过了就不能存入数据库),而不进行别的验证和执行别的代码,所以远离了注入式攻击,使数据库更安全。

2.删除文档

删除文档的基本方法是remove:

db.collectionName.remove()
db.collectionName.remove({})
db.collectionName.remove(condition)
db.collectionName.drop()

前三种都是删除集合中的文档,第一个和第二个是一样的,都不指定删除的条件,这样会删除掉集合中所有的文档,第四个是删除该集合,连索引都删除了,如果要清除整个集合,直接删除集合的效率比删除集合中的所有文档更快。第三个指定了一个条件,比如删除people集合中name为mary的所有文档:

db.people.remove({"name" : "mary"})

3.更新文档

更新文档的基本方法是update,虽然上面讲到了save在"_id"一样的时候也有这种功效,当然我们一般是不会以"_id"为更新条件的:

db.collectionName.uodate(condition, modifier, upsert, multi)

update有四个参数,condition是查询文档,用来查询出要修改的文档,modifier是修改器文档,描述对查找到的文档做哪些修改,upsert表示如果没有该文档就插入这个心文档,默认为false,multi表示是否更新查询到的所有文档,默认为false,所以只更新查询到的第一个文档。但是我们平时经常用到的还是前两个参数,如果有必要就用后两个参数。因为更新操作是原子的,所以当有很多更新同时发生时,最后一次的更新操作才是最后的结果。下面我们将name为mary的文档age改为20:

> db.people.find()
{ "_id" : ObjectId("53a3a0b7abda49d7dfce102c"), "name" : "mary", "age" : 30, "country" : "US" }
> db.people.update({"name" : "mary"}, {"age" : 20})
> db.people.find()
{ "_id" : ObjectId("53a3a0b7abda49d7dfce102c"), "age" : 20 }

但是最后的结果却出乎我们的预料,name字段和country字段都没有了,这样的update是用后面的文档替换查询到的文档,所以结果是正确的,只是我们的操作错误了。那我们每次更新不都要将原来的数据再写一次么,这样比写SQL更复杂啊,不过还有一种改进方式,在shell中将查询到的文档赋值给一个变量,然后再修改,最后在将这个变量替换原来的查询结果:

方式一:
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 30, "country" : "US" }
> db.people.update({"name" : "mary"}, {"name" : "mary", "age" : 20})
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 20 }
方式二:
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 30, "country" : "US" }
> person = db.people.findOne()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 30, "country" : "US"}
> person.age = 20
> delete person.country
true
> db.people.update({"name" : "mary"}, person)
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 20 }

查询出name为mary的文档赋值给person,