12 May 2015

前言

出于准备工作的需要,趁着还在学校,还能借书,学习一下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有以下三个特点:

  1. 轻量级
  2. 跨平台(其数据逻辑结构和数据存储是平台无关的)
  3. 效率高。

命名空间: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操作命令如下:

  1. 超级用户相关:
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()  #删除当前的数据库
  1. 增删改
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()  #删除所有的记录
  1. 索引
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')
  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'})  #子对象的查找
  1. 管理
db.deliver_status.dataSize()  #查看collection数据的大小
db.deliver_status.stats()  #查看colleciont状态
db.deliver_status.totalIndexSize() #查询所有索引的大小
  1. 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了,完全没有用来做有用的事情。

参考文献

  1. MongoDB 权威指南,Kristina等著,陈显峰译,人民邮电出版社
  2. MongoDB Group - ITeye技术社区:http://mongodb.group.iteye.com/ (群粗中有些分享资料)
  3. MongoDB: http://www.mongodb.org/
  4. mongoDB Cookbook:



傲娇的使用Disqus