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

mongoDB学习笔记整理

2012-09-05 14:32 429 查看
学习官方文档介绍做下面一点笔记

1,文档型数据库(文件存储格式为BSON)

设计数据库时需要考虑下面几点:

由于mongodb可以存储物理文件,需要考虑什么时候存储资源,什么时候仅仅存储资源的链接
需要存储多少个collection,都是些什么
是否需要原子操作,原子操作支持文档内部,跨文档原子操作不支持
为了让查询速度更快,需要设计怎样的索引
针对collection如何分片,用作分片的key是什么,这个key也会用作分片后查询的输入值

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


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