目前学习使用mongodb,主要是一个项目中使用到了地理位置服务相关的内容。比如发布一个活动,客户端自动将当前位置获取到一同存储到后端;可以利用数据库中的地理位置信息实现如“附近的活动,附近的人;在地图上展现附近的活动、人”等功能。
原先的这些location功能实现是一并采用mysql建表实现的。
[mysql]
CREATE TABLE `i_event_locations` (
`event_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '活动id',
`name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Name',
`address` varchar(255) NOT NULL COMMENT 'Address',
`lat` double NOT NULL DEFAULT '0' COMMENT '纬度',
`lng` double NOT NULL DEFAULT '0' COMMENT '经度',
`created` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`updated` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
UNIQUE KEY `event_id` (`event_id`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Location Table'
[/mysql]
表结构就是如此,需要说明的是活动event与location是一对一的关系,event_id就是活动id即是外键也是主键。
这样的结构在后端业务中怎么实现呢,主要思路就是通过传入经纬度得到一个表达式distance,在event与location进行join联表查询时按distance进行desc的排序,得到最近的event list;如果需要限制在10km之间,那么就需要加上where distance < 10000
[php]
/**
* 返回计算距离的SQL语句表达式
* @param $lat
* @param $lng
*/
private function get_distance_exp($lat, $lng){
return DB::expr("(2 * 6378.137* ASIN(SQRT(POW(SIN(PI() * ($lat - lat)/360), 2) + COS(PI() * {$lat} / 180)
* COS(lat * PI() / 180) * POW(SIN(PI() * ({$lng} - lng) / 360), 2))))*1000");
}
[/php]
就是上面这个东东,我也没看明白是什么原理。总之它返回的是以米为单位的一个数据值。
弊端确实有,需要联表查询且还要计算表达式可能会比较慢。(详细性能测试暂没有进行)
确实需要了解下性能方面的问题了,不能只听别人说mysql这样处理很慢就觉得慢,听别人说mongodb用的快就用;
mongodb是文档化schema free(自由格式)的数据库,开源有商业团队支持,高速发展,应用广泛;与mysql不存在谁取代谁的问题,只是什么环境下哪种数据库更适合。
回到那个地理位置检索的问题,将i_event_locations转变为mongodb collection后,可以根据建立的loc二维索引进行当前location 经纬度的检索,这样就得到了所有的event_id值,在通过这些event_id的到符合需求条件的event活动;
这样也就不用进行联表查询以及地理位置的表达式运算(这部分目前直接交予索引处理了);
MongoDB的特性 来自blog.nosqlfan.com
- 简单的查询语句,没有Join操作
- 文档型存储,其数据是用二进制的Json格式Bson存储的。其数据就像Ruby的hashes,或者Python的字典,或者PHP的数组
- Sharding,MongoDB提供auto-sharding实现数据的扩展性
- GridFS,MongoDB的提供的文件存储API
- 数组索引,你可以对文档中的某个数组属性建立索引
- MapReduce,可以用于进行复杂的统计和并行计算
- 高性能,通过使用mmap和定时fsync的方法,避免了频繁IO,使其性能更高
MongoDB的优点
- 高性能,速度非常快(如果你的内存足够的话)
- 没有固定的表结构,不用为了修改表结构而进行数据迁移
- 查询语言简单,容易上手
- 使用Sharding实现水平扩展
- 部署方便
使用MongoDB,你得记住以下几点:
- MongoDB 假设你有大磁盘空间
- MongoDB 假设你的内存也足够大于放下你的热数据
- MongoDB 假设你是部署在64位系统上的(32位有2G的限制,试用还可以)
- MongoDB 假设你的系统是little-endian的
- MongoDB 假设你有多台机器(并不专注于单机可靠性)
- MongoDB 假设你希望用安全换性能,同时允许你用性能换安全
MongoDB在下面领域不太擅长
- 不太稳定,特别是auto-sharding目前还有很多问题
- 不支持SQL,这意味着你很多通过SQL接口的工具不再适用
- 持久化,MongoDB单机可靠性不太好,宕机可能丢失一段时间的数据
- 相关文档比较少,新功能都有这个问题
- 相关人才比较难找,这也是新功能的问题之一
安装mongodb
要学习使用,首先下载mongodb
windows 32位平台下也可以安装但是数据容量最大只有2G,可以作为测试学习之用,不推荐作为工作生产环境。
Linux 64位则最大可以达到128T,所以推荐linux平台上部署。
mongodb下载后解压到目录后
进入bin里面执行下面命令
--dbpath 是mongodb数据库文档存储目录,--logpath 是mongodb的日志文件,--install 则是将mongodb安装到系统服务里面去。要了解更多命令执行mongod --help查看。
执行完成后检查mongodb.log要是没有错误信息,则通过http://localhost:27017可以看到
You are trying to access MongoDB on the native driver port. For http diagnostic access, add 1000 to the port number 则说明成功了。而访问http://localhost:28017 可以查看mongodb的监控信息。
注意这里第一次安装没有成功时,mongodb_data里面新生成的的mongod.lock 可能会被锁住,再次安装时会产生
dbexit: really exiting now
这时需要删除掉mongod.lock,重新进行安装。
注意在windows xp 下面安装时可能会出现“无法定位程序输入点 InterlockedCompareExchange64 于动态链接库KERNEL32.dll上”
原因就是这样
“Mongodb最新的开发分支已经不再支持xp,也就是说vista是最陈旧支持的客户端,windows server2003是最陈旧的windows服务器版本,但是2.0的分支任然支持着xp,V2.0.6是最新也是最后一个新版本支持xp。因此最好还 是在 linux 下开发吧。”
我的windows xp安装版本是
db version v2.0.6, pdfile version 4.5
Wed Feb 27 22:24:02 git version: e1c0cbc25863f6356aa4e31375add7bb49fb05bc
所以还是推荐最新平台最新版本吧。
MongoDB shell命令
MongoDB自带一个JavaScript shell, 以命令行与MongoDB实例交互。
可以执行管理操作,检查运行实例等
启动Shell:
$ ./mongo
可以运行任何JavaScript程序,还可以利用JavaScript的标准库。所以所有的对象方法都是区分大小写的,输入命令时要注意!
可以定义和调用JavaScript函数。
可以使用多行命令。
show dbs; -- 查看数据库
show databases; --查看数据库
use dbname; --选择数据库
show collections; --查看表
show tables; --查看表
db.tablename.find(); -- tablename的数据查询,
db.tablename.find({a: 'k'}); -- 对a字段进行数据k的匹配检索查询
db.tablename.find({a:'k'}).sort({id: -1}); --对a字段进行数据k的匹配检索查询且按照id进行倒叙排列,反之1则是正序排列了
db.tablename.find({a:'k'}).limit(5); --对a字段进行数据k的匹配检索查询只返回最初5条记录
db.tablename.find({a:'k'}).skip(2).limit(5); --对a字段进行数据k的匹配检索查询从第二条开始返回5条记录。skip()限制返回记录的开始点,就等于是mysql里面的offset
db.tablename.save({a: 'haha', id:'22}); -- 添加新的记录
db.tablename.update({id: 22}, {$set: {a: 'xixi'}}); -- 对id为22的字段a进行修改;即第一个参数是query(也就是mysql中的where),第二个参数修改内容集合,还有第三个参数就是update时的一些设置;
db.tablename.remove({id:22}, 1); -- 删除id为22的记录,第一个参数为where,第二个参数为limit,比如为1则只删除查询结果中的1条
db.tablename.drop(); --删除当前的表,drop()不同于remove(),remove只是清空数据,drop直接数据连同表删除了
db.dropDatabase(); --删除当前的数据库
db.location.ensureIndex({loc: 2d}) --对location构建2d 地理位置的索引,{id: 1}设置为1则是正序索引,-1倒序索引;1(ascending),-1(descending)
db.location.getIndexes(); --查看location的索引。
db.location.getIndexKeys(); --查看location的索引keys。
db.location.dropIndex('loc'); --按索引名字删除索引,注意这里不是字段的名字
db.location.count(); --查询表中记录数
mongodb数据导出,不是进入到mongo shell里面去,
mongodump -d databasename -o D:/dirname -u username -p --等于是mysql的mysqldump命令一样。
有导出当然有导入咯。
mongorestore -d test D:\mongodb_bak\test -u admin -p --还原test数据库
mongodb不推荐使用mongoexport与mongoimport来进行导出与导入;而是推荐使用mongodump与mongorestore来进行。
mongodb权限验证
mongodb 默认是无权限验证就可访问的。所以需要开启auth用户验证,需要在mongod安装时加上 --auth参数
Control Access to MongoDB Instances with Authentication
加入--auth参数安装好mongodb后;可以使用下面的进行用户设置
-- 超级管理员,所有数据库都能访问
use admin
db.addUser("username","password");
-- 普通管理员
user exampledb
db.addUser("alex","alex");
alex只能对exampledb进行查看管理
-- 只读管理员,登录后只有读的权限
user exampledb
db.addUser("alex","alex",true);
对比之前的无认证环境,可以看到现在都出现了need login的信息内容了。
那首先就login
db.auth("username","password"); 返回的是1,表示这个用户匹配上了,也就是登录成功了。
还有一种就是keyFile的方式,
Specify the path to a key file to store authentication information. This option is only useful for the connection between replica set members.
指定的密钥文件的路径存储身份验证信息。此选项只适用于副本集成员之间的连接。(没明白这个副本集成员之间的链接是什么意思)
同样是在安装时指定 mongod --keyFile filepath
keyFile 必须小于1kb,只是包含base64的字符;密钥文件没有组且具有 “world” permissions on UNIX systems
+++++
unix world permissions
unix的世界权限是个啥呢?Unix Permissions
找到了一篇解答
The third group of permission bits corresponds to the world permissions. These are the permissions granted to everyone.
也就是每一个人都具有这个权限,任何人都有这个权限。
+++++
在windows system上面不检测权限。
更多请看:Security Considerations for Replica Sets
更多命令看这里吧
学习资料推荐