mongodb学习笔记
前言
出于准备工作的需要,趁着还在学校,还能借书,学习一下MongoDB。
MongoDB官网:http://www.mongodb.org/
这篇笔记大概是一年前写的,那时还在学校。对将要参加工作的事情激动不已。面试过了之后,数着从前辈哪里听到新的名词,mongodb,redis,git之流。 从图书馆借阅了一本又一本相关的书,虽然都没看完,但当时的那种心情,以后估计都不会再有了。
序言
MongoDB灵活的文档模型适合大数据,高并发,弱事务的互联网应用。理解MongoDB的设计哲学,正视其优缺点。
MongoDB中文社区,陈显峰,Peter Membrey。在未来,MongoDB,Nginx,Linux,PHP/Python/Ruby VS LAMP。
关系型数据库vs NoSQL,MonogDB简单易用,松散模式,易于灵活调整,支持复杂属性,建立索引,对字段进行原子性改变。SourceForge应用MongoDB,NoSQL,MongoDB程序员友好,系统管理员灾难。
大型互联网公司的MySQL应用发展:备份->缓存层->集群->重构应用逻辑->更多硬件。
MongoDB实用主义: 不去迎合所有人,在功能和复杂性之间的平衡。 web应用的关键功能: 索引,复制,分片,丰富的查询语法,灵活的数据模型,较好的速度。
CSDN上的MongoDB社区(http://mongodb.csdn.net)
数据库的多种表示形式,数字世界支柱。10gen Paas平台。Mysql中关系型数据库,固定的Schema,实体-属性-值模型。Mongodb的查询语法和Rails中的查询语法。二级索引-B树。速度和持久性,复制与持久性,写硬盘和写内存的权衡。
入门
Oracle | MongoDB ----------------------------- | -------------------------------- 数据库实例(database instance) | MongoDB实例 模式(schema) | 数据库(database) 表(table) | 集合(collection) 行(row) | 文档(document) rowid | _id Join | DBRef
MongoDB基本概念:文档(数据基本单元),集合没有模式的表,单个实例多个独立的数据库(独立的集合和权限),JavaScript Shell,_id键(默认主键,默认ObjectID对象)。
文档:MongoDB的核心,多个键及其关联值的有序放置,编程语言的对应表示(数据结构:map,hash或者字典)。JavaScript中使用对象(JSON)表示文档。
BSON(Binary JSON 的简称):JSON文档对象的二进制编码格式,Mongodb数据库文件存储的格式。BSON同JSON一样支持往其它文档对象和数组中再插入文档对象和数组,同时扩展了JSON的数据类型。如:BSON有Date类型和BinDate类型。时间和日期的类型,貌似在web应用程序中,时间和日期的作用相当的强大,Rails中也内建了很多对时间和日期的支持和扩展。
BSON被比作二进制的交换格式,如同Protocol Buffers,但BSON比它更“schema-less”,非常好的灵活性但空间占用稍微大一点。
BSON有以下三个特点:
- 轻量级
- 跨平台(其数据逻辑结构和数据存储是平台无关的)
- 效率高。
命名空间:MongoDB存储BSON对象到collections,这一系列的数据库名和collection名被称为一个命名空间。如同:java.util.List;用来管理数据库中的数据。
索引(Index): mongodb可以对某个字段建立索引,可以建立组合索引、唯一索引,也可以删除索引,建立索引就意味着增加空间开销。默认情况下每个表都会有一个唯一索引:_id(随机生成的全球唯一的12位数据,分布式),如果插入数据时没有指定_id,Mongodb的进程会自动生成一个_id,为了充分利用已有索引,减少空间开销,最好是自己指定一个unique的key为_id,通常用对象的ID比较合适,比如商品的ID。
体系结构
运行的MongoDB的数据库可以看作MongoDB server,该Server由实例和数据库组成。一般而言,一个实例以及多个对应的数据库,也可以多个实例,多个数据库。MongoDB中的物理文件(数据库文件,日志文件的集合)称为数据库。数据库磁盘相关的物理文件: dbname.ns,dbname.0,dbname.1,dbname.2等。
存储机制
MongoDB内部含有预分配空间的机制,预分配文件使用0进行填充,避免由于数据暴增的磁盘压力。数据库文件,重分配空间,2倍指数递增,2G封顶。表的命名空间(db.xxx.xx)和索引(index)的命名空间这些元数据都集中在*.ns文件中。 命名空间和盘区的关系,命名空间可以包含不同的盘区(非连续),数据库中的命名空间:.test,bar,baz ,$freelist,preallocated space。
文档中的键值对是有序唯一,值可以是字符串,其他数据类型或整个文档,键是唯一的(不能包含\0,.,$以及_开头的键)
集合虽然没有模式,但将同类型的文档放到一个集合中大有裨益(开发,查询,索引)。
集合的命名:不为空串,不包含\0和$,不以system.开头。
包含子集合(以.字符分开)的MongoDB工具:
- GridFS存储大文件的协议,以子集合来存储文件的元数据,看到了Ruby中很多相关的包。
- MongoDB的web控制台通过子集合的方式将数据组织在BDTOP中。
- 驱动程序提供的语法糖,提供访问特定子集合的方法
数据库:多个文档组成集合,多个集合组成数据库。将一个应用所有数据放在同一数据库中。其命名约束:不为空,不包含特书字符,小写,不大于64字符(数据库名变成文件系统里的文件)。特殊数据库:admin,local,config。数据库命名空间:cms.blog.posts。
备注:在公司的数据库模型中,没能体会Mongodb和Mysql的不同,除了声明的语句格式稍微有些不同,存在诸如index,scope这样的语句申明。后来发现,这是Mongoid的功能,
安装
开源项目的安装无非就那几种方法:1.源代码 2.二进制包 3.包管理器
其中,包管理器安装最简单:以mongodb开头的包有如下的这些:mongodb,mongodb-clients,mongodb-dev,mongodb-server。
MongoDB网络服务:mongod,27017端口,/data/db目录,http服务器(28017端口,可以在浏览器中打开),界面如下:
MongoDB Shell:mongo,JavaScript解释器(可使用JavaScript标准库),MongoDB客户端
- 运行shell: ./mongo
- 基本操作:创建(insert),读取(find),更新(updata),删除(remove)
- 集合名和数据库函数重名的问题。
- 数据类型:基本数据类型(类似JSON,除了null,布尔,数字,字符串,数组和对象这些类型外,添加了一些新的类型:32位整数,符号,对象Id,日期,正则表达式,代码,二进制数据)
Mongodb管理
一个mongod服务可以有建立多个数据库,每个数据库可以有多张表,这里的表名叫collection,每个collection可以存放多个文档(document),每个文档都以BSON(binary json)的形式存放于硬盘中,因此可以存储比较复杂的数据类型。它是以单文档(single document)为单位存储的,也可以任意给一个或一批文档新增或删除字段,而不会对其它文档造成影响,这就是所谓的schema-free,这也是文档型数据库最主要的优点。跟一般的key-value数据库不一样的是,它的value中存储了结构信息,所以你又可以像关系型数据库那样对某些域进行读写、统计等操作。
Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,可以实现类似关系数据库单表查询的绝大部分功能,支持对数据建立索引。Mongo还可以解决海量数据的查询效率,根据官方文档,当数据量达到50GB以上数据时,Mongo数据库访问速度是MySQL 10 倍以上。
总结:强大的查询功能,海量数据。
启动和配置MongoDB
命令行启动,配置文件启动(mongod -f xxx.conf)。Mongodb的默认管理端口为 28017,其Web管理端口在该 port 的基础上+1000。 Mongodb的主要一般参数为:
- dbpath:数据文件存放路径,每个数据库会在其中创建一个子目录,用于防止同一个实例多次运行的 mongod.lock 也保存在此目录中。
- logpath:错误日志文件
- logappend:错误日志采用追加模式(默认是覆写模式)
- bind_ip:对外服务的绑定 ip,一般设置为空,及绑定在本机所有可用 ip 上,如有需要可以单独指定
- port:对外服务端口。Web 管理端口在这个 port 的基础上+1000
- fork:以后台 Daemon 形式运行服务
- journal:开启日志功能,通过保存操作日志来降低单机故障的恢复时间,在 1.8 版本后正式加入,取代在 1.7.5 版本中的 dur 参数。
- syncdelay:系统同步刷新磁盘的时间,单位为秒,默认是 60 秒。
- directoryperdb:每个 db 存放在单独的目录中,建议设置该参数。与 MySQL 的独立表空间类似
- maxConns:最大连接数
- repairpath:执行 repair 时的临时目录。在如果没有开启 journal,异常 down 机后重启,必须执行 repair操作。
MongoDB的参数分为一般参数,windows参数,replication参数,replica set参数,以及隐含参数。Mongodb的参数没有设置内存大小的参数,其使用的os mmnap,自生不提供缓存数据文件数据。
停止Mongodb数据库:ctrl + c 和 shutdownServer()指令,或者kill命令。
命令工具:
- bsondump: 将 bson 格式的文件转储为 json 格式的数据
- mongo: 客户端命令行工具,其实也是一个 js 解释器,支持 js 语法
- mongod: 数据库服务端,每个实例启动一个进程,可以 fork 为后台运行
- mongodump/mongorestore: 数据库备份和恢复工具
- mongoexport/mongoimport: 数据导出和导入工具
- mongofiles: GridFS管理工具,可实现二制文件的存取
- mongos: 分片路由,如果使用了sharding功能,则应用程序连接的是mongos而不是mongod
- mongosniff: 这一工具的作用类似于 tcpdump,不同的是他只监控MongoDB相关的包请求,并且是以指定的可读性的形式输出
- mongostat: 实时性能监控工具
JavaScript Shell
Mongodb的数据库可以通过 JavaScript Shell进行操作,但是该命令行交互工具受到JavaScript语法一些限制。一些常用的Shell操作命令如下:
- 超级用户相关:
use admin #进入数据库admin
db.addUser('name','pwd') #增加或修改用户密码
db.system.users.find() #查看用户列表
db.auth('name','pwd') #用户认证
db.removeUser('name') #删除用户
show users #查看所有用户
show dbs #查看所有数据库
show collections #查看所有的collection
db.printCollectionStats() #查看各collection的状态
db.printReplicationInfo() #查看主从复制状态
db.repairDatabase() #修复数据库
db.setProfilingLevel(1) #设置记录profiling,0=off 1=slow 2=all
show profile #查看profiling
db.copyDatabase('mail_addr','mail_addr_tmp') #拷贝数据库
db.mail_addr.drop() #删除collection
db.dropDatabase() #删除当前的数据库
- 增删改
db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]}) #存储嵌套的对象
#这里注意,1.不需要预先创建集合,在第一次插入数据时会自动创建。 2.文档中可以存储任何的数据,非常灵活不需要特定申明 3.插入数据都会有一个名为_id的ID。
db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']}) #存储数组对象,save方法
db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true) #根据query条件修改,如果不存在则插入,允许修改多条记录
db.foo.remove({'yy':5}) #删除yy=5的记录
db.foo.remove() #删除所有的记录
- 索引
db.foo.ensureIndex({firstname: 1, lastname: 1}, {unique: true}); #增加索引:1(ascending),-1(descending)
db.user_addr.ensureIndex({'Al.Em': 1}) #索引子对象
db.foo.getIndexes() #查看索引信息
db.foo.getIndexKeys() #根据索引名删除索引
db.user_addr.dropIndex('Al.Em_1')
- 查询(query somothing)
查询:
db.foo.find() #查找所有,find方法返回一个游标对象,shell将会迭代这个游标。
db.foo.findOne() #查找一条记录
db.foo.find({'msg':'Hello 1'}).limit(10) #根据条件检索10条记录
查询并排序(find & sort )
db.deliver_status.find({'From':'ixigua@sina.com'}).sort({'Dt',-1})
db.deliver_status.find().sort({'Ct':-1}).limit(1)
db.user_addr.count() #count操作
db.foo.distinct('msg') #distinct操作,查询指定列,去重复
db.foo.find({"timestamp": {"$gte" : 2}}) #”<=”操作 gte-小于等于
db.foo.find({'address.city':'beijing'}) #子对象的查找
- 管理
db.deliver_status.dataSize() #查看collection数据的大小
db.deliver_status.stats() #查看colleciont状态
db.deliver_status.totalIndexSize() #查询所有索引的大小
- advanced queries:高级查询
条件操作符
$gt : <,$lt : <,$gte: <=
$lte: >,$ne : !=,$in : in
$nin: not in,$all: all,$not: 反匹配(1.3.3及以上版本)
一些基本的查询的例子:
查询 name <> “bruce” and age <= 18 的数据: db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
查询creation_date > '2010-01-01' and creation_date < '2010-11-31'
的数据: db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
查询 age in (20,22,24,26) 的数据: db.users.find({age: {$in: [20,22,24,26]}});
查询 age取模10等于0 的数据:
db.users.find('this.age % 10 == 0');
或者
db.users.find({age : {$mod : [10, 0]}});
查询不匹配name=B*
带头的记录,^是取反操作: db.users.find({name: {$not: /^B.*/}});
mongodb的返回字段总是包含_id
,和其他的相关字段。
$exists判断字段是否存在,例如: db.users.find({name: {$exists: true}});
$type判断字段类型
查询所有name字段是字符类型的: db.users.find({name: {$type: 2}});
查询所有age字段是整型的: db.users.find({age: {$type: 16}});
查询语法固然非常的重要,但是,每次用命令行查找太过繁琐。所以,找了一个GUI工具 - Robomongo。
应用部分
MongoDB的Node.js的支持,MongoDB原本就是专为JavaScript设计的数据库。和Nodejs的结合自然是天衣无缝。
MongoDB的Ruby支持,安装Ruby驱动,sudo gem install mongo
(将会安装两个包,bson和mongo)。不过,工作中使用的是mongodb的ORM - mongoid。
注意:部署MongoDB时,需要考虑如何调优,如何处理复制和分片,怎么维护集群?
使用express(4.x)开发nodejs时,通过PORT=4000 npm start
指定特定端口,启动web服务器。
后记
这篇笔记写的真烂,基本就是在抄书,没什么意思。真不知道,当时的自己怎么这么无聊。一腔热血都洒在了Copy & Paste了,完全没有用来做有用的事情。
参考文献
- MongoDB 权威指南,Kristina等著,陈显峰译,人民邮电出版社
- MongoDB Group - ITeye技术社区:http://mongodb.group.iteye.com/ (群粗中有些分享资料)
- MongoDB: http://www.mongodb.org/
- mongoDB Cookbook:
傲娇的使用Disqus