学习官方文档介绍做下面一点笔记
1,文档型数据库(文件存储格式为BSON)
设计数据库时需要考虑下面几点:
2,全索引
mongodb采用b-tree作为索引的数据结构
> db.a.save({"name":"penjin","age":25}) > db.a.ensureIndex({"name":1}) > db.a.find({"age":25}) //slow > db.a.find({"name":"penjin"}) //fast通过db.a.getIndexes()可以查看所包含的索引,其中_id索引是默认的不可删除
此外可以给子文档添加索引
> db.a.save({"name":"ciaos","age":25,"address":{"city":"shenzhen","code":"100871"}}) > db.a.ensureIndex({"address.city":1})还可以指定多个key的联合索引,值1代表升序,-1代表降序
dropIndex,reIndex等函数可以删除索引和重置索引
3,复制备份&高可用性
mongod --port 27017 --dbpath ./db1 --journal --fork --logpath 1.log --master mongod --port 27018 --dbpath ./db2 --journal --fork --logpath 2.log --slave mongod --port 27019 --dbpath ./db3 --journal --fork --logpath 3.log --slave
用mongo控制台客户端连接master数据库进行操作,save数据库中也会同步备份
mongodb还提供replSet的集群方式,使用--replSet设定集群名称,官方推荐使用这种集群方式。
mongod.exe --dbpath d:\data --replSet myset --port 27017 mongod.exe --dbpath e:\data --replSet myset --port 27018 mongod.exe --dbpath f:\data --replSet myset --port 27019 mongo.exe > rs.initiate() > rs.add("computer-name:27018") > rs.add("computer-name:27019") > rs.status()
可以将启动参数写到配置文件如下(分别创建三个conf文件,指定三个端口,27017.conf文件如下):
dbpath = d:/data logpath = d:/log.log port = 27017 directoryperdb = true journal = true replSet = myset rest = true oplogSize = 24 logappend = true启动方式:mongod.exe --quiet -f 27017.conf
客户端连接集群的方式如下(PHP版本)
<?php $m = new Mongo("mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019",array("replicaSet" => "myset")); //deal with database ?>
这种集群方式没有主从概念,当某个数据库挂掉后会智能地连接其他可用的数据库。这种架构比简单的主从复制更加容易维护,同样能达到减轻读写压力的目的。
详细内容可以参照《使用MongoDB Replica Sets的三种架构》
生产环境下还可以根据业务考虑开启日志功能,防止意外down掉时重启修复,不过据我测试,还是会丢失几条数据。(我在测试集群时,发现三个问题:1,数据库down掉后修复可能会一直处于RECOVERING状态,把该数据库文件删除后重启才能正常同步;2,replset方式配置集群时必须保证同时有2个数据库正常运行,只有一个数据库运行时会自动从主库转备库,无法写入——测试v2.2.0版本,不知道以后的版本会不会修复这个问题;3,集群中如果有机器down掉,对设置了slaveOk的读有性能影响,容易出现突刺。总之感觉mongodb还是不靠谱,不要用来存储重要内容)
4,自动分片
mongodb提供分布式的安装部署,只需要进行简单的配置就能做拓展存取海量的数据
mongod.exe --dbpath d:\data --port 27017 mongos.exe --port 27016 --configdb=127.0.0.1:27017 //调度 mongod.exe --dbpath f:\data --port 27028 mongod.exe --dbpath g:\data --port 27019 mongo.exe 127.0.0.1:27016/admin > db.runCommand({"addshard":"127.0.0.1:27028"}) > db.runCommand({"addshard":"127.0.0.1:27019"}) > db.runCommand({"addshard":"127.0.0.1:27017"}) > db.runCommand({"enablesharding":"test"}) //启用分片 > db.runCommand({shardcollection:"test.book",key:{_id:1}}) //设置分片的collection然后连接27016端口的test数据库进行操作就可以分片插入了,对外表现也是一个完整的数据库。具体使用方法参照官方文档,还可以指定每个分片的大小
详细的配置方案可以参看这篇博客介绍
5,丰富的查询功能
丰富的文档型数据库查询,很多关系型数据库的查询都有对应的语句支持,可以参照这篇文档介绍
6,原子操作
提供$inc,$set,$unset,$push,$pushAll,$pop,$pull,$pullAll,$rename,$bit等“运算子”,需要注意的是由于php语言中$符号有特殊含义,为了避免误用需要对$转义(或者修改php.ini中表示变量的符号)
7,Map/Reduce
(下面是官方文档的例子)
$ ./mongo > db.things.insert( { _id : 1, tags : ['dog', 'cat'] } ); > db.things.insert( { _id : 2, tags : ['cat'] } ); > db.things.insert( { _id : 3, tags : ['mouse', 'cat', 'dog'] } ); > db.things.insert( { _id : 4, tags : [] } ); > // map function > m = function(){ ... this.tags.forEach( ... function(z){ ... emit( z , { count : 1 } ); ... } ... ); ...}; > // reduce function > r = function( key , values ){ ... var total = 0; ... for ( var i=0; i<values.length; i++ ) ... total += values[i].count; ... return { count : total }; ...}; > res = db.things.mapReduce(m, r, { out : "myoutput" } ); > res { "result" : "myoutput", "timeMillis" : 12, "counts" : { "input" : 4, "emit" : 6, "output" : 3 }, "ok" : 1, } > db.myoutput.find() {"_id" : "cat" , "value" : {"count" : 3}} {"_id" : "dog" , "value" : {"count" : 2}} {"_id" : "mouse" , "value" : {"count" : 1}} > db.myoutput.drop()
通过生成中间collection保存结果,通过在mongodb数据层增加计算功能可以减少网络数据的通信传输量,不过map/reduce的性能怎么样我没具体测试
8,GridFS
见另外一篇博客介绍——用mongo存储小文件
9,提供各种语言的驱动
下面是官方C语言驱动的使用示例
#include<stdio.h> #include"mongo.h" int main(){ //connect mongo conn[1]; int status = mongo_connect(conn,"10.6.2.15",27017); if(status != MONGO_OK){ switch(conn->err){ case MONGO_CONN_SUCCESS: printf( "connection succeeded\n" ); break; case MONGO_CONN_NO_SOCKET: printf( "no socket\n" ); return 1; case MONGO_CONN_FAIL: printf( "connection failed\n" ); return 1; case MONGO_CONN_NOT_MASTER: printf( "not master\n" ); return 1; } } //combine bson data bson b[1]; bson_init(b); bson_append_new_oid(b,"_id"); bson_append_string(b,"name","Joe"); bson_append_int(b,"age",33); bson_finish(b); mongo_insert(conn, "test.people", b, NULL); bson_destroy(b); //query and print mongo_cursor cursor[1]; mongo_cursor_init(cursor, conn, "test.people"); while(mongo_cursor_next(cursor) == MONGO_OK) bson_print(&cursor->current); mongo_cursor_destroy(cursor); //disconnect mongo_destroy(conn); return 0; }
输出结果如下:
_id : 7 50480e353a0e480200000000 name : 2 Joe age : 16 33
更多介绍参照此处