MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。 在高负载的情况下,添加更多的节点,可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。

安装

mongodb 安装很简单,不管windows还是linux直接去官方下载压缩包解压就行了。本人使用的linux

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-amazon-3.2.8.tgz
tar xvpzf mongodb-linux-x86_64-amazon-3.2.8.tgz
mv mongodb-linux-x86_64-ubuntu1204-3.0.3 /usr/local/mongodb

添加配置文档

vim /usr/local/mongodb/mongodb.conf

添加配置 dbpath=/data/mongodb 创建软连接,并创建目录,{mongo_dir} 表示mongodb的安装目录

cd /usr/local/bin
ln -s {mongo_dir}/bin/mongod
ln -s {mongo_dir}/bin/mongo

mkdir -p /data/mongodb

启动

启动很简单

mongod -f /usr/local/mongodb/mongodb.conf

启动成功之后,用mongo客户端连接服务器

用户管理

mongodb创建用户老版本和新版不同,新版屏蔽了addUser方法

use admin

db.addUser("root", "123456", false); #老版本数据库

db.createUser({user: "root",pwd: "123456",roles: [{ role: "root", db: "admin" }]}); #新版数据库

db.system.users.find().pretty(); #查询用户

db.removeUser("root"); #删除用户

addUser方法的三个参数分别是用户名,密码,第三个参数是表示是否是只读用户,默认是false

createUser是新版的创建用户的方法

user : 用户名
pwd : 密码
roles : 指定用户的角色,可以用一个空数组给新用户设定空角色;在roles字段,可以指定内置角色和用户定义的角色

角色可选值如下

  • Read:允许用户读取指定数据库
  • readWrite:允许用户读写指定数据库
  • dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
  • userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
  • clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
  • readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
  • readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
  • userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
  • dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
  • root:只在admin数据库中可用。超级账号,超级权限

插入文档

mongodb不需要单独创建数据库和数据表(mongo中叫集合),很方便,由于时nosql,数据的格式也是很灵活,是一个json对象 当执行插入的时候,使用的驱动程序会将数据保存成BSON(关于BSON,这个后续文章会讲到,这里暂且不表)的形式,然后将其送入数据库,数据库解析BSON,会做简单的验证,主要检验是否包含”_id”,并且文档不超过4MB,然后就简单的将文档插入数据库中。不过个人认为这样会带来一些好处或者坏的影响,最明显的副作用就是允许插入无效数据,好处就是这样貌似你也没有办法对mongodb进行注入攻击了,也就是说mongodb对注入攻击时天生免疫的(听起来很牛逼)。

use user;   #切换数据库,如果不存在则创建

> show tables;
system.indexes
system.users
system.version
> db.blog.insert({id:1, title:"this is a test", hits:1}); #往blog数据表中插入一个文档,如果blog表不存在则自动创建
WriteResult({ "nInserted" : 1 })

更新文档

MongoDB 使用 update() 和 save() 方法来更新集合中的文档。这里需要特别注明的是:更新的操作时原子性的,若是两个更新同时发生,则先到达服务器的先执行,接着执行另外一个,相互有冲突的更新可以火速传递,并不会产生干扰。

update(query, data, upsert, multi);

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的。
  • data : 要更新的数据
  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
db.blog.update({id:1}, {id:2, title:"new title", hits:2}, false, true); //文档替换
db.blog.update({id:1}, {$set : {id:2, title:"new title"}, false, true); //使用修改器修改

有一个问题是:update其实正确的解释是替换文档,并不是真正意义上的更新,因为通常文档只会有一部分需要更新的, 这个时候你就需要用到原子的更新修改器,这可以使得这部分更新极为高效,更新修改器时一种特殊的键,用来制定复杂的更新操作,比如调整,增加或者删除文档的key,还可能是操作数据或者内嵌文档。 mongo 有很多修改器的,下面列举几个

  • $inc 增加某个字段的值 {$inc : {hits:10}} 把点击率加10
  • $set 修改或者新增部分字段,而不是整个文档替换,这个用的比较经常,毕竟一般我们只改某个文档的部分内容,很少有整个替换的。
  • $push 修改数组的值
> db.blog.insert({id:2, title:"new blog", tags:["fuck", "shit"]});
WriteResult({ "nInserted" : 1 })
> db.blog.find({id:2});
{ "_id" : ObjectId("57ac4b860776d82c21a31d77"), "id" : 2, "title" : "new blog", "tags" : [ "fuck", "shit" ] }
> db.blog.update({id:2}, {$push : {tags:"oh mygod"}});
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.find({id:2});
{ "_id" : ObjectId("57ac4b860776d82c21a31d77"), "id" : 2, "title" : "new blog", "tags" : [ "fuck", "shit", "oh mygod" ] }

查询文档

mongo的查询功能很强大,几乎可以跟sql数据库相媲美,尤其是还提供了很多操作符查询的 “$gt” 、”$gte”、 “$lt”、 “$lte”、”null查询”、”$all”、”$size”、”$in”、”$nin”、 “$and”、”$nor”、”$not”、”$or”、”$exists”、”$mod”、”$regex”、”$where”、”$slice”、”$elemMatch”…

下面举几个例子

db.blog.find();  #查找所有文档
db.blog.find({id:1}); #查找id=1的文档
db.user.find({name:/jack/i}); #正则查询,相当于sql中like查询
db.user.find({age:{$gte: 16, $lt:18}}); #where age > 16 AND age < 18
db.user.find({$or:{name:"xiaoming", sex:"M"}}); #where name=xiaoyang OR sex=M
db.user.find({name : {$in:["xiaoming","xiaoyang", "xiaowang"]}}); #where name IN('xiaoming', 'xiaoyang', 'xiaowang')
db.user.find({name:"xiaoyang"}).skip(10).limit(20).sort({id:-1}); #分页查询,并且order by id desc
...

删除文档

db.remove(query, justOne);

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的。
  • justOne : 默认为true,之删除匹配到的第一文档,如果设置为true,则会删除匹配到的所有文档
db.blog.remove({id:1});
db.user.remove({status:0}, false); #删除所有未审核的用户

删除文档速度时很快的,几乎在一瞬间完成的,但是如果你要清空整个文档,并且文档的数据量又大,建议你直接删除集合(然后重建索引)会更快。比如一个含有100w个文档的集合,你一条一条删除可能要花费近50秒的时间,但是直接删除集合却只要0.01秒不到。

MongoDB优缺点分析

通过这两天的简单学习,发现mongodb的优势还是很明显的

  1. 速度比较快,我使用php的Mongodb扩展进行测试,插入100w条记录平均耗时65秒,每秒钟插入15000条左右,这速度甩mysql几条街
  2. 文档的格式相当自由,这对于关系行数据库优势还是比较大的,对于一些不规则的数据结构比如商品的属性什么的,每个中商品的属性都不一样,各类的都有,这要是用关系型数据库去实现得建N个表,折腾半天才能勉强实现,但是如果用mongo的话,一个表就可以解决,而且逻辑非常建档,相当方便。
  3. 相对于mysql的读写分离主从配置,分表分库什么的,mongo的分片还是简单的多,所以说mongo的扩展性和高可用也是有保障的。
  4. 内置了GridFS GridFS是一个出色的分布式文件系统,可以支持海量的数据存储,能够满足对大数据集的快速范围查询。
  5. 内置了强大的查询功能,支持各种复杂查询,尤其时$where操作符查询,使得查询几乎能做任何事情了,可以跟sql数据库达到相同的效果,甚至能实现更复杂的查询。

当然,缺点也是有的

  1. 对于已经习惯了写sql来查询的小伙伴来说mongo的查询条件确实有点复杂,没有sql那么简单直接,尤其一些分组查询之类的,虽然能实现,但是确实是比较麻烦的。
  2. 不支持事务,这个确实是个蛋疼的问题,这就注定了一些业务的数据肯定是不能用mongo来存储了,如果非要的话可能时要自己在应用层实现事务了。不过这也不是太大的问题,大不了把那些数据存回mysql之类的关系型数据库了。
  3. mongodb占用的空间比较大,其实mongo的效率是用空间换来的,首先BSON这种文档格式就不是很省空间,而且mongo的一些操作也是有点浪费空间,比如mongo在删除数据的时候其实并没有真正的释放磁盘空间,为避免记录删除后的数据的大规模挪动,原记录空间不删除,只标记“已删除”即可,以后还可以重复利用。
  4. 目前我还没有发现,以后再慢慢找。。。