MongoDB入门

《MongoDB权威指南》的读书笔记。

Table of Contents

  • 1 开始使用MongoDB
    • 1.1 启动MongoDB
    • 1.2 核心概念
      • 1.2.1 文档
      • 1.2.2 集合
      • 1.2.3 ObjectId
    • 1.3 数据类型
  • 2 插入、更新、删除及查询文档
    • 2.1 插入
    • 2.2 更新
      • 2.2.1 文档整体替换
      • 2.2.2 $set修改器
      • 2.2.3 $inc修改器
      • 2.2.4 $push修改器
      • 2.2.5 修改器速度
    • 2.3 删除
    • 2.4 查询
      • 2.4.1 指定返回的键
      • 2.4.2 查询范围
      • 2.4.3 正则表达式
      • 2.4.4 查询数组
      • 2.4.5 查询内嵌文档
  • 3 创建索引
  • 4 管理MongoDB
    • 4.1 监控页面
    • 4.2 停止MongoDB
    • 4.3 备份和修复
      • 4.3.1 停机备份
      • 4.3.2 mongodump
      • 4.3.3 fsync
      • 4.3.4 从属备份
      • 4.3.5 修复

1 开始使用MongoDB

1.1 启动MongoDB

Windows平台下在Cygwin中启动MongoDB,要注意的是:

  • 需要手动创建/data/db文件夹 mkdir -p /data/db
  • 要为/data/db设置正确的权限 chown -R user:group /data

现在就可以启动MongoDB了。我是将data文件夹建在MongoDB文件夹里了,所以可以使用dbpath参数指定目录。

./mongod --dbpath ../data/db &

MongoDB的Shell是一个功能完备的JavaScript解释器,可以运行任何JavaScript程序。Shell会在启动时自动连接到本地的MongoDB服务器。

./mongo

1.2 核心概念

1.2.1 文档

文档是MongoDB的核心概念,由多个键及其关联的值有序地放在一起便是文档。对应关系型数据库中行的概念。集合就是一组文档,就如同数据库表。但集合是无模式的,这意味着一个集合里面的文档可以是各式各样的。

1.2.2 集合

在关系型数据库中,如果要保存people其address,一般会拆分成两个表中的两行。在MongoDB中,就可以将address文档直接嵌入people文档中。这样做也有坏处,因为MongoDB会储存更多重复的数据,这样是反规范化的。

1.2.3 ObjectId

在客户端生成体现了MongoDB的设计理念:能从服务器端转移到驱动程序来做的事,就尽量转移。这种理念背后的原因是,即便是像MongoDB这样的可扩展数据库,扩展应用层也要比扩展数据库层容易得多。此外在客户端生成ObjectId,驱动程序能够提供更加丰富的API。

1.3 数据类型

MongoDB的文档类似于JSON。但JSON仅有6中数据类型,表现力有限。MongoDB在保留JSON基本的键/值对的基础上,添加了一些其他数据类型。

2 插入、更新、删除及查询文档

2.1 插入

当执行插入时,使用的驱动程序会将数据转换成BSON的形式。数据库解析BSON,检验是否包含“_id”并且文档不超过4MB,除此之外不做别的数据验证,就只是简单地将文档原样存入数据库中。坏处是允许插入无效的数据,好处是让数据库更加安全,远离注入式攻击。

db.blog.insert({"title" : "Hello MongoDB", "author" : "cdai"})

db.blog.find()
{ "_id" : ObjectId("514580655da8aea55cb4b7a8"), "title" : "Hello MongoDB", "author" : "cdai" }

2.2 更新

2.2.1 文档整体替换

当模式结构发生较大变化,完全用一个新文档替代匹配的文档。

db.blog.update({"author" : "cdai"}, {"username" : "cdai", "comments" : ["good"]})

db.blog.find()
{ "_id" : ObjectId("514580655da8aea55cb4b7a8"), "username" : "cdai", "comments" : [ "good" ] }

2.2.2 $set修改器

如果键不存在就创建它,这对更新模式,增加用户定义的键来说非常方便。

db.blog.update({"username" : "cdai"}, {"$set" : {"pageviews" : 52}})

db.blog.find()
{ "_id" : ObjectId("514580655da8aea55cb4b7a8"), "comments" : [ "good" ], "pageviews" : 52, "username" : "cdai" }

2.2.3 $inc修改器

$inc只能用于整数、长整数或双精度浮点数。

db.blog.update({"username" : "cdai"}, {"$inc" : {"pageviews" : 1}})

db.blog.find()
{ "_id" : ObjectId("514580655da8aea55cb4b7a8"), "comments" : [ "good" ], "pageviews" : 53, "username" : "cdai" }

2.2.4 $push修改器

$push会向已有的数组末尾加入一个元素,要是不存在会创建一个新数组。

db.blog.update({"username" : "cdai"}, {"$push" : {"comments" : "not bad"}})

db.blog.find()
{ "_id" : ObjectId("514580655da8aea55cb4b7a8"), "comments" : [ "good", "not bad" ], "pageviews" : 53, "username" : "cdai" }

2.2.5 修改器速度

$inc能就地修改,因为不需要改变文档的大小。而数组修改器可能更改了文档的大小,就会慢一些。MongoDB预留了些补白给文档,来适应大小变化。但是要是超出了原来的空间,最后还是要分配一块新的空间。

2.3 删除

删除集合里所有数据。不会删除集合本身,原有的索引也会保留。

db.blog.remove()

删除集合。速度很快,整个集合都被删除,所有的索引也都不见了。

db.drop_collection("blog")

2.4 查询

2.4.1 指定返回的键

find或findOne函数的第二个参数指定想要/剔除的键。

db.blog.find({"username" : "cdai"}, {"pageviews" : 1})
{ "_id" : ObjectId("514580655da8aea55cb4b7a8"), "pageviews" : 53 }

db.blog.find({"username" : "cdai"}, {"pageviews" : 0})
{ "_id" : ObjectId("514580655da8aea55cb4b7a8"), "comments" : [ "good", "not bad" ], "username" : "cdai" }

2.4.2 查询范围

$lt、$lte、$gt、$gte就是全部的比较运算符。

db.blog.findOne({"pageviews" : {"$gte" : 1, "$lte" : 100}})
{
        "_id" : ObjectId("514580655da8aea55cb4b7a8"),
        "comments" : [
                "good",
                "not bad"
        ],
        "pageviews" : 53,
        "username" : "cdai"
}

类似的运算符还有$ne、$in、$not、$or等,用法类似,就不一一介绍了。

2.4.3 正则表达式

MongoDB使用Perl兼容的PCRE库来匹配正则表达式。

db.blog.find({"username" : /dai/i})
{ "_id" : ObjectId("514580655da8aea55cb4b7a8"), "comments" : [ "good", "not bad" ], "pageviews" : 53, "username" : "cdai" }

2.4.4 查询数组

2.4.5 查询内嵌文档

3 创建索引

MongoDB的索引几乎与传统的关系型数据库索引一模一样。

db.blog.ensureIndex({"username" : 1})
Sun Mar 17 15:41:46 [conn4] build index test.blog { username: 1.0 }
Sun Mar 17 15:41:46 [conn4] build index done.  scanned 1 total records. 0.036 secs

如果索引包含N个键,则对于前几个键的查询都会有帮助。比如有个索引{"a" : 1, "b" : 1, "c" : 1},实际上是有了{"a" : 1},{"a" : 1, "b" : 1}和{"a" : 1, "b" : 1, "c" : 1}三个索引。

有些时候最有效的方法居然是不使用索引。一般来说,要是查询返回集合中一半以上的结果,用表扫描会比几乎每条文档都要查索引要高效一些。

所以,建立索引时要考虑如下问题。 (1)会做什么样的查询?其中哪些键需要索引? (2)每个键的索引方向是怎样的? (3)如何应对扩展?有没有种不同的键的排列可以使常用数据更多地保留在内存中?

4 管理MongoDB

4.1 监控页面

通过–rest选项开启REST支持,可以更好地使用监控页面。

./mongod --dbpath ../data/db/ --rest &

4.2 停止MongoDB

使用kill或kill -2停止MongoDB,会等到当前运行的操作或者文件预分配完成,关闭所有打开的链接,将缓存的数据刷新到磁盘,最后停止。千万不要向运行中的MongoDB发送SIGKILL(kill -9)信号。这会导致上面的步骤全被忽略,数据库直接关闭。

use admin
switched to db admin
db.shutdownServer()

4.3 备份和修复

4.3.1 停机备份

在运行MongoDB时复制数据目录不太安全,所以就得先把服务器关了,再复制数据目录。假设服务器安全关闭了,数据库目录中就是关闭那一刻数据的快照。

4.3.2 mongodump

mongodump使用普通的查询机制,所以产生的备份不一定是服务器数据的实时快照。服务器在备份过程中处理写入时尤为明显。

4.3.3 fsync

fsync命令会强制服务器将所有缓冲区写入磁盘。还可以选择上锁对数据库的进一步写入,直到释放锁为止。要是数据库运行在有快照功能的文件系统上,这个会很有用。

4.3.4 从属备份

因为不太在乎从属服务器的性能或是能不能读写,于是就能随意选择上面的3种备份方式。

4.3.5 修复

修复数据库的过程实际上非常简单:将所有的文档导出然后马上导入,忽略那些无效的文档。完成以后,会重新建立索引。修复数据库还能起到压缩数据的作用。闲置的空间(删除大量文档后腾出的空间)在修复后被重新回收。


你可能感兴趣的:(MongoDB入门)