Category Archives: NOSQL

MongoDB中时间比实际时间小8小时的解决方法

现象

存储到数据库的时间总是比实际时间小8小时。

原因

存储在mongodb中的时间是标准时间UTC +0:00 , 而中国的时区是+8.00 。

解决办法

如果使用C#的Mongodb.Driver驱动,则只需要在实体的时间属性上添加一个特性并指时区就可以了。

比如:

[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime EntryTime
{get;set;}

此特性需要引用MongoDB.Bson.dll 。

using MongoDB.Bson.Serialization.Attributes;

 

 

Redis2.4.13 安装部署

1 Redis 介绍

Redis是Remote Dictionary Server的缩写。他本质上一个Key/Value数据库,与Memcached类似的NoSQL型数据库,但是他的数据可以持久化的保存在磁盘上,解决了服务重启后数据不丢失的问题,他的值可以是string(字符串)、list(列表)、sets(集合)或者是ordered sets(被排序的集合),所有的数据类型都具有push/pop、add/remove、执行服务端的并集、交集、两个sets集中的差别等等操作,这些操作都是具有原子性的,Redis还支持各种不同的排序能力

2Redis功能简介

l Redis的Sharding:目前,redis server没有提供类似mongodb那样的shard功能,只能在client端,通过一致性hash算法实现,当前Redis不支持故障冗余,在集群中不能在线增加或删除Redis

l Redis的master/slave复制:

n 一个master支持多个slave

n Slave可以接受其他slave的连接来替代他连接master

n 复制在master、在slave都是非阻塞的。

n 复制被利用来提供可扩展性,在slave端只提供查询功能及数据的冗余

l Redis的Virtual Memory功能:

u 因性能问题,2.4版本 VM机制彻底废弃

u redis的vm模式在实践中存在一些问题.

u 我使用过redis2.0.2, 发现当vm模式打开的时候, 并发连 接数在1500以上时, redis latency会大大增加.平均每个请求的latency会超过4000ms, 观察redis的进程cpu占用率, 会超过100%. 最后迫于无奈,关掉了redis的vm功能. 此时并发连接不变的情况下,redis的latency下降到2ms以下. cpu占用率下降到1%.

l Redis的附加档案(AOF)功能:Redis通过配置的策略将数据集保存到aof中,当Redis挂掉后能够通过aof恢复到挂掉前的状态

l 提供批量写入功能

l 事务:允许让一组命令进入队列一次性执行,在执行的过程中不穿插其它命令(Redis的单线程保证)。

l 管道:一次性提交多个命令(如果只是进行一些设置,命令之间不需要依赖前置命令结果的话,可以提高不少效率)。

3 Redis机构示意图

4 Redis安装

Shell>wget http://redis.googlecode.com/files/redis-2.4.13.tar.gz #下载程序

Shell >tar –zxvf redis-2.4.13.tar.gz #解压程序包

Shell > cd redis-2.4.13 #进入解压目录

Shell> make #进行编译安装

Shell > make test #测试是否成功

该版本安装不需要configure 和make install ,make编译安装后SRC目录下会多几个文件

redis-server #Redis 服务器启动命令

redis-benchmark #Redis服务启动后查看相关服务信息命令

redis-check-aof

redis-check-dump

redis-cli #Redis 命令行操作工具

为了部署规范管理方便操作如下:

· shell>mkdir -p bin

· shell>mkdir -p conf

· shell>mkdir -p logs

· shell>mkdir -p data

· shell>cd src

· shell>cp redis-server redis-cli redis-benchmark redis-stat ../bin

· shell>cd ..

shell·>cp redis.conf conf

调整配置文件调整

daemonize yes #后台运行

pidfile /opt/redis-2.4.13/bin/redis.pid #pid路径

port6379 #监听端口

logfile /opt/redis-2.4.13logs/stdout.log #日志文件路径

dbfilename /opt/redis-2.4.13/data/dump.rdb #数据库文件路径
5 Redis服务启动与停止

Shell>bin/redis-server /opt/redis-2.4.13/conf/redis.conf #服务启动,直接运行在后台

Shell>ps -ef |grep redis #查看是否有进程

Shell>netstat –ntlp |grep 6379 #查看默认监听端口

Shell>bin/ redis-benchmark #性能测试工具,测试该系统下读写性能

Shell>bin/redis-cli #命令行工具,测试是否正常

Shell >bin/redis-cli shutdown #关闭Redis服务
6 Redis配置文件详解

配置文件参数说明:

1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程

i. daemonize no

2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定

i. pidfile /var/run/redis.pid

3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字

i. port 6379

4. 绑定的主机地址

i. bind 127.0.0.1

5. 当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能

i. timeout 300 #

如果应用中使用了连接池,最好设置为0,表示不使用服务器自动断开的功能,否则容易出现 java.net.SocketTimeoutException: Read timedout 或者是 It seems like server has closedthe connection 这样的异常,应用中千万要控制住连接数,打开的连接一定要关闭

6. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose

i. loglevel verbose

7. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null

i. logfile stdout

8. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id

i. databases 16

9. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合

i. save <seconds> <changes>

ii. Redis默认配置文件中提供了三个条件:

iii. save 900 1

iv. save 300 10

v. save 60 10000

vi. 分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。

10. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大

i. rdbcompression yes

11. 指定本地数据库文件名,默认值为dump.rdb

i. dbfilename dump.rdb

12. 指定本地数据库存放目录

i. dir ./

13. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步

i. slaveof <masterip> <masterport>

14. 当master服务设置了密码保护时,slav服务连接master的密码

i. masterauth <master-password>

15. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭

i. requirepass foobared

16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息

i. maxclients 128

17. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区

i. maxmemory <bytes>

18. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no

i. appendonly no

19. 指定更新日志文件名,默认为appendonly.aof

i. appendfilename appendonly.aof

20. 指定更新日志条件,共有3个可选值:

i. no:表示等操作系统进行数据缓存同步到磁盘(快)

ii. always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)

iii. everysec:表示每秒同步一次(折衷,默认值)

iv. appendfsync everysec

21. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)

i. vm-enabled no

22. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享

i. vm-swap-file /tmp/redis.swap

23. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0

i. vm-max-memory 0

24. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值

i. vm-page-size 32

25. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。

i. vm-pages 134217728

26. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4

i. vm-max-threads 4

27. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启

i. glueoutputbuf yes

28. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法

i. hash-max-zipmap-entries 6

ii. hash-max-zipmap-value 512

29. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)

a) activerehashing yes

30. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件

include /path/to/local.conf
7 多端口运行的配置

redis是单进程的服务,所以咱得根据CPU的数目,确定究竟该运行几个实例,这样才能最好的发挥性能优势,比如服务器是8core的,那最好能够运行8个实例,这里只以第一个作为举例

1. 假设redis的安装目录在/opt/redis下面,即这个目录下包含了redis-benchmark redis-cli redis-server这几个可执行文件,现在在下面新建一个servers的文件夹,存放所有的实例

mkdir -p /opt/redis/servers/0/
mkdir -p /opt/redis/servers/0/conf
mkdir -p /opt/redis/servers/0/data
mkdir -p /opt/redis/servers/0/run
mkdir -p /opt/redis/servers/0/logs

2. 然后我们需要拷贝一份配置文件到该实例的路径下

cp redis.conf /opt/redis/servers/0/conf

3. 修改配置文件中的下列内容

pidfile /opt/redis/servers/0/run/redis.pid
port 6380
logfile /opt/redis/servers/0/logs/stdout.log
dbfilename /opt/redis/servers/0/data/dump.rdb

4. 启动停止

./redis-server /opt/redis/servers/0/conf/redis.conf #启动服务

./redis-cli -p 6380shutdown #停止服务
8 Redis维护常用命令

1、../bin/redis-cli keys\* #查看所有键值信息

[root@monitordata]# ../bin/redis-cli keys \*

1)”name”

2)”name1″

2、../bin/redis-cli info #查看redis运行状态

[root@monitordata]# ../bin/redis-cli info

redis_version:2.4.13

redis_git_sha1:00000000

redis_git_dirty:0

arch_bits:64

multiplexing_api:epoll

gcc_version:4.4.6

process_id:2738

uptime_in_seconds:6888

uptime_in_days:0

lru_clock:1508888

used_cpu_sys:0.08

used_cpu_user:0.02

used_cpu_sys_children:0.01

used_cpu_user_children:0.00

connected_clients:2

connected_slaves:0

client_longest_output_list:0

client_biggest_input_buf:0

blocked_clients:0

used_memory:734976

used_memory_human:717.75K

used_memory_rss:7323648

used_memory_peak:726504

used_memory_peak_human:709.48K

mem_fragmentation_ratio:9.96

mem_allocator:jemalloc-2.2.5

loading:0

aof_enabled:0

changes_since_last_save:0

bgsave_in_progress:0

last_save_time:1336293648

bgrewriteaof_in_progress:0

total_connections_received:8

total_commands_processed:19

expired_keys:0

evicted_keys:0

keyspace_hits:9

keyspace_misses:2

pubsub_channels:0

pubsub_patterns:0

latest_fork_usec:1679

vm_enabled:0

role:master

db0:keys=2,expires=0

from:http://hi.baidu.com/webwatch/item/47c7e3df6f4a37f592a97456

mongodb配置文件详解

运行时数据库配置

命令行配置文件界面可为 MongoDB 管理员提供大量选项和设置,用于控制数据库系统的运行。该文档提供了通用配置以及普通使用案例的最佳配置示例。

尽管两种界面都可访问相同的选项和设置集合,但该文档主要使用配置文件界面。如果您使用控制脚本或操作系统的程序包来运行 MongoDB,很可能已经有一个配置文件,该文件位于 /etc/mogondb.conf。检查/etc/init.d/mongod /etc/rc.d/mongod 脚本的内容确定这一点,以确保控制脚本会以适当的配置文件启动 mongod(见下文)。

要使用该配置启动 MongoDB 实例,按以下格式发出一个命令:

 mongod --config /etc/mongodb.conf mongod -f /etc/mongodb.conf

修改系统上的 /etc/mongodb.conf 文件中的值,以控制数据库实例的配置。

启动、停止和运行数据库

请看以下基本配置:

 fork = true bind_ip = 127.0.0.1 port = 27017 quiet = true dbpath = /srv/mongodb logpath = /var/log/mongodb/mongod.log logappend = true journal = true

对于大多数独立服务器,这是足够使用的基本配置。它作了几个假定,但请看以下说明:

  • fork true,可为 mongod 启用后台模式 ,使(如 “forks”)MongoDB 从当前会话中分离,并允许您将数据库作为传统服务器来运行。
  • bind_ip 127.0.0.1,它会强制服务器仅侦听本地主机 IP 上的请求。仅绑定至安全接口,该接口可由应用程序级系统通过系统网络过滤(如“防火墙”)系统提供的访问控制权限来访问。
  • 端口27017,这是数据库实例的默认 MongoDB 端口。MongoDB 可绑定至任何端口。您也可以使用网络过滤工具来过滤访问权限。

    注意

    UNIX 类系统要求超级用户权限才能将进程连接至低于 1000 的端口。

  • quiet true。这会禁止输出/日志文件中的所有条目,但最重要的条目除外。在正常操作中,这是避免日志噪音的最佳操作。在诊断或测试情况中,将该值设为false。使用 setParameter 可在运行时过程中修改该设置。
  • dbpath /srv/mongodb,它指定 MongoDB 存储其数据文件的位置。/srv/mongodb /var/lib/mongodb 都是常用的位置。mongod 运行时所在的用户帐户将需要对该目录具有读写权限。
  • logpath /var/log/mongodb/mongod.log,其中 mongod 将写入其输出。如果您不设置此值,mongod 将把所有输出写入到标准输出(即 stdout)中。
  • logappendtrue,确保 mongod 在服务器启动操作之后不会覆盖现有的日志文件。
  • journal true,这样将启用 日志
    日志可确保单实例写入耐久性。 64 位版本的 mongod默认情况下启用日志。因此,此设置可能是多余的。

如果采用默认配置,有些值可能是多余的。但是,在很多情况下,明确地描述配置可促进对整个系统的理解。

安全考虑事项

下面的配置选项集合对于限制对 mongod 实例的访问权限很有用。请考虑以下配置:

 bind_ip = 127.0.0.1 bind_ip = 10.8.0.10 bind_ip = 192.168.4.24 nounixsocket = true auth = true

考虑对这些配置决定的下列解释:

  • bind_ip”有三个值:127.0.0.1,本地主机接口;10.8.0.10,通常用于本地网络和 VPN 接口的专用 IP 地址;192.168.4.24,通常用于本地网络的专用网络接口。

    由于生产 MongoDB 实例需要从多个数据库服务器访问,因此务必将 MongoDB 绑定到多个可从您的应用程序服务器访问的接口。同时,务必将这些接口限制为在网络层实现控制和保护的接口。

  • nounixsocket”为 true,这样将会禁用 UNIX 套接字,而在默认情况下为启用。这样可限制对本地系统的访问。使用共享权限连续运行 MongoDB 时这种情况很理想,但在大多数情况下影响极小。
  • auth”为 true,这样将在 MongoDB 中启用身份验证。如果已启用,第一次登录时您需要通过本地主机接口建立连接,以创建用户凭证。

另见

安全和身份验证”维基页面。

复制和分片配置

复制配置

副本集配置简单明了,只需要 replSet 有一个在集合的所有成员之间保持一致的值即可。请考虑以下配置:

 replSet = set0

使用描述性的副本集名称。配置后,使用 mongo壳将主机添加到副本集。

另见

副本集重新配置”。

要对副本集启用身份验证,请添加下列项:

 keyfile = /srv/mongodb/keyfile

1.8 版新特性:针对副本集;1.9.1 版针对分片副本集。

设置keyFile以启用身份验证,并指定一个密钥文件供副本集成员使用,确定相互之间何时进行身份验证。密钥文件的内容可以任意规定,但在副本集 以及连接到该集的 mongos 实例的所有成员上必须相同。 keyfile 的大小必须小于 1 KB,可以只包含 base64 编码集字符,文件在 UNIX 系统上不得拥有组或“世界”权限。

另见

副本集重新配置”部分,以了解在操作期间更改副本集的流程方面的信息。

此外,请考虑“副本集安全性”部分以了解使用副本集配置身份验证的信息。

最后,请参阅“复制” 索引和“复制基础”文档,以了解关于 MongoDB 中的复制以及一般副本集配置的信息。

分片配置

分片需要若干采用不同配置的 mongod 实例。配置服务器存储群集的元数据,而群集将数据发布到一个或多个分片服务器。

注意

配置服务器不是副本集

设置一个或三个“配置服务器”实例作为正常 mongod 实例,然后添加下列配置选项:

 configsrv = true bind_ip = 10.8.0.12 port = 27001

这样将创建一个运行于专用 IP 地址:10.8.0.12,端口:27001 的配置服务器。确保没有端口冲突,且配置服务器可从您的“mongos”和“mongod”实例访问。

要设置分片,请配置两个或更多 mongod实例,使用您的基本配置并添加 shardsvr 设置:

 shardsvr = true

最后建立群集,使用下列设置来配置至少一个 mongos 进程:

 configdb = 10.8.0.12:27001 chunkSize = 64

您可以通过在逗号分隔列表的表格中指定主机名和端口来指定多个 configdb 实例。通常,避免将 chunkSize 修改为默认值 64 以外的值,[1]并应当确保此设置在所有 mongos实例中都保持一致。

[1] 数据块大小默认值为 64 MB,可在最均匀的数据分布(较小的数据块最佳)和最小化数据块迁移(较大的数据块最佳)之间实现理想的平衡。

另见

分片”维基页面,以了解关于分片和分片群集配置的详细信息。

在同一系统上运行多个数据库实例

在很多情况下,建议不要在单个系统上运行多个 mongod 实例。有些类型的部署[2]可能会出于测试目的而需要在单个系统上运行多个 mongod

在这些情况下,为每个实例应用基本配置,但是请考虑下列配置值:

 dbpath = /srv/mongodb/db0/ pidfileath = /srv/mongodb/db0.pid

dbpath 值控制 mongod 实例的数据目录的位置。确保每个数据库都有明确且标签正确的数据目录。pidfilepath 控制 mongod 进程将其pid 文件放置到的位置。由于此轨迹取决于具体的 mongod文件,因此务必确保该文件是唯一的且标签正确,以便于开始和停止这些进程。

创建附加控制脚本并/或调整现有 MongoDB 的配置以及控制这些进程所需的控制脚本。

[2] 使用 SSD 或其他高性能磁盘的单租户系统可为多 mongod 实例提供可接受的性能水平。此外,您还会发现,使用小工作集的多数据库在单系统上的性能可以接受。

诊断配置

下列配置选项控制多种用于诊断的 mongod 行为。下列使用针对一般生产目的调整的默认值:

 slowms = 50 profile = 3 verbose = true diaglog = 3 objcheck = true cpu = true

使用基本配置,如果您遇到一些未知的问题或性能问题,根据需要添加这些选项:

  • slowms 配置数据库探查器的阈值以考虑“缓慢”的查询。默认值为 100 毫秒。如果数据库探查器未返回有用的结果,则设置较低的值。请参阅“优化”维基页面,以了解 MongoDB 中的优化操作的详细信息。
  • profile 设置数据库探查器 等级。探查器默认情况下不活动,因为那样可能会影响探查器本身的性能。除非为此设置指定了一个值,否则不对查询进行探查。
  • verbose 启用详细记录模式,在此模式下可修改 mongod 输出并增加记录以包括更多的事件。仅在遇到不能正常反映日志记录级别的问题时使用此选项。如果您需要达到更详细的级别,请考虑下列选项:
     v = true vv = true vvv = true vvvv = true vvvvv = true

    增加的每个 v 级别都会额外地增加记录的详细程度。verbose 选项相当于 v=true

  • diaglog 启用诊断日志记录。等级 3 记录所有读写选项。
  • objcheck 强制 mongod 在收到来自客户端的请求时全部进行验证。使用此选项确保无效的请求不会导致错误,特别是在不可信客户机运行数据库时。此选项可能会影响数据库的性能。
  • cpu 强制 mongod 报告
    写锁定所用的最后时间间隔的百分比。时间间隔通常为 4 秒,日志中的每个输出行都包括自上次报告以来的实际时间间隔和写锁定所用的时间百分比。

    from:http://blog.sina.com.cn/s/blog_9c5dff2f01012n0f.html

探索 MongoDB

MongoDB 是什么?

近几年来,我们已经看到不同于传统关系模型的数据库管理系统越来越受欢迎。它的核心是 NoSQL 概念,这个共同的术语表示不使用 SQL 语言与数据库交互的数据库软件。比较著名的 NoSQL 项目之一就是 MongoDB,一个开放源码、面向文档的数据库,它在类似于 JSON 的文档集合存储数据。MongoDB 相比其他 NoSQL 数据库的优势之一是它强大的、基于文档的查询语言,由于查询非常容易转换,这使得从关系数据库到 MongoDB 的过渡变得简单。

MongoDB 是用 C++ 语言编写的。它在类似于 JSON 的文档中存储数据(使用 BSON,一个 JSON 的二进制版本),存储数据的方式是使用键/值对。MongoDB 优于其他文档数据库的一个特性是它很容易将 SQL 语句转换成 MongoDB 查询函数调用。这使得当前使用关系数据库的组织很容易迁移到 MongoDB。它也很容易安装和使用,有二进制和驱动程序两种形式,兼容主流操作系统和编程语言。

MongoDB 是一个开放源码项目,其数据库基于 GNU AGPL (Affero General Public License) version 3.0 的许可。此许可是 GNU GPL 的一个修正版,它弥补了版权限制不适用于软件使用而仅适用软件分发的漏洞。这对于在云中存储而不经常安装在客户端设备上的软件当然是重要的。使用常规 GPL ,您会感觉到实际上无法进行分发,因此潜在地规避了许可条款。

AGPL 只适用于它自己的数据库应用程序,不适用于 MongoDB 的其他组成部分。允许开发人员从各种编程语言连接 MongoDB 的官方驱动程序在 Apache License Version 2.0 许可下分发。 MongoDB 文档的使用基于 Creative Commons 许可。

面向文档的数据库

面向文档的数据库与传统关系数据库有很大不同。与在类似于表的固定结构中存储数据不同,面向文档的数据库在松散定义的文档中存储数据。利用关系数据库管理系统(RDBMS)表,如果您需要添加一个新的列,您需要改变表本身的定义,这会将该列添加到每一条现有的记录(虽然可能是一个空值)。这是由于 RDBMS 严格的基于模式的设计。然而,利用文档时,您可在不改变任何其他文档的情况下为个别文档添加新属性。这是因为面向文档的数据库在设计上通常非模式化的。

另一个基本差异是面向文档的数据库不在文档之间规定严格的关系。这有助于维护它们的非模式化设计。这与十分依赖规范化数据存储关系的关系型数据库有很大不同。与在一个单独的存储区存储相关数据不同,在文档数据库中它们被嵌入文档本身,这要比将引用存储到另一个存储相关数据的文档中要快得多,因为每个引用都需要一个附加查询。

对于许多应用程序来说,如果它需要在一个父文档中包含自成体系的数据,这种面向文档的数据库非常适合。一个好的示例(可在 MongoDB 文档中找到)是博客文章和评论。评论只适用于一篇文章,所以把它们从该文章分开是无意义的。在 MongoDB 中,有关博客文章的文档只需要一个 comments 属性来存储该文章的评论。而如果使用关系数据库,则可能需要一个带 ID 主关键字的 comments 表、一个带 ID 主关键字的 posts 表和一个中间的映射表 post_comments,此映射表用于定义哪个评论属于哪篇文章。这为本应很简单的事增加了不必要的复杂性。

不过,如果您必须分开存储相关数据,在 MongoDB 中也可以简单地使用一个独立的集合来完成。另一个好的示例是您把客户订单信息存储在 MongoDB 文档中。它通常包含以下信息:客户、订单、订单条目和产品信息。使用 MongoDB ,您可以在独立的集合中存储客户、产品和订单,但是您需要把订单项数据嵌入在相关的订单文档中。然后,您需要使用类似于外部关键字的 ID 来引用 productscustomers 集合。由于这种混合方法非常简单,使得 MongoDB 成为已习惯于使用 SQL 的开发 人员的极好选择。如上所述,应该花点时间细心地为每个单独用例选择合适的方法,因为相比于从其他集合中引用数据,采用在文档中嵌入数据的方法将获得显著的性能收益。

功能概览

MongoDB 不仅仅是一个基本的键/值对存储数据库,让我们简单地看一下它的其他特性:

  • 可用于 Windows®、Mac OS X、Linux® 和 Solaris 的官方二进制版本,可用于自构建的源代码分发
  • 可用于 C、C#、C++、Haskell、Java™、JavaScript、Perl、PHP、Python、Ruby 和 Scala 的官方驱动程序,以及广泛可用于其他语言的社区支持的驱动程序。
  • Ad-hoc JavaScript 查询让您能够使用基于任何文档属性的任何条件来查找数据。这些查询对应于 SQL 查询的功能,使 SQL 开发人员能够很直观地编写 MongoDB 查询。
  • 支持查询中的正则表达式
  • MongoDB 查询结果存储在提供过滤、聚合和排序等一系列功能的游标中,包括 limit()skip()sort()count()distinct()group()
  • 高级聚合的 map/reduce实现
  • 使用 GridFS 的大文件存储
  • 类似于 RDBMS 的属性索引支持,您可以直接在文档的选定属性上创建索引
  • 使用提示、解释计划和分析的查询优化特性
  • 类似于 MySQL 的主/从复制
  • 基于集合的对象存储,在需要规范化数据时允许参考查询
  • 通过自动分片功能水平扩展
  • 高性能无争用并发机制的即时更新
  • 在线 shell 让您能够不安装 MongoDB 即可试用
  • 深入的文档资料,已出版或正在写作中的多本图书

回页首

安装 MongoDB

幸运的是,MongoDB 在各种平台上的安装都非常简单。二进制发行版在 Windows、Mac OS X、 Linux 和 Solaris 上都可以使用,同时,各种包管理器为其他系统提供了简单的安装和设置选项。如果您够勇敢,可以自己编译源代码。在本节中,您将学会如何在 Windows 和 OS X 上安装 MongoDB,在 Windows 上将进程设置为服务或在 OS X 上将进程设置为守护程序。

在 Windows 上安装

在 Windows 上安装 MongoDB 十分简单。在 Web 浏览器中,转到 http://www.mongodb.org/downloads 并下载适用于 Windows 的最新版本的稳定产品。如果您正使用 64 位版本的 Windows 操作系统,建议使用 64 位版本。如果您不确定,就使用 32 位版本。

把压缩文件解压到 C:\ 驱动器,这将创建一个名称类似于 mongodb-win32-i386-1.6.4 的文件夹。为了简便,将这个文件夹重命名为 mongo 。接下来,需要创建一个数据目录。在 Windows 资源管理器中,转到 C:\ 驱动器的根目录下并创建一个名为 data 的新文件夹。在此文件夹中,创建一个名为 db 的文件夹。

您现在可以启动 MongoDB 服务器。使用 Windows 资源管理器导航至 C:\mongo\bin 并双击 mongod.exe。关闭打开的命令提示符窗口将会停止 MongoDB 服务器。因此,将 MongoDB 服务器设置为 Windows 服务更为方便。我们现在来完成。

打开命令提示符窗口 (启动 > 运行 >,输入 cmd 并按 确定),然后发出清单 1 中的命令。

清单 1. 将 MongoDB 服务器设置为一个服务

				
> cd \mongo\bin
> mongod --install --logpath c:\mongo\logs --logappend 
--bind_ip 127.0.0.1 --directoryperdb

您将看到清单 2 中的输出。

清单 2. 创建服务成功

				
all output going to c:\mongo\logs
Creating service MongoDB.
Service creation successful.
Service can be started from the command line via 'net start "MongoDB"'.

将 Mongo 作为服务安装后,您现在可以用以下命令启动它:> net start "MongoDB"

您将看到清单 3 中的输出。

清单 3. Mongo 成功启动

				
The Mongo DB service is starting.
The Mongo DB service was started successfully.

您现在可以运行 MongoDB shell 客户端。如果现在有一个命令提示符窗口打开,确认位于 c:\mongo\bin 文件夹中并输入以下命令:> mongo.

另一种方法是,在 Windows 资源管理器中导航至 C:\mongo\bin 并双击 mongo.exe。无论选择哪种方法来启动 shell,您都应看到如清单 4中所示的提示。

清单 4. 启动 shelll

				
MongoDB shell version: 1.8.1
connecting to: test
>

如果您不想在 Mac OS X 计算机上设置 MongoDB,现在可以跳过本节的下一部分,转到“入门指南”,您将学习如何使用 shell 客户端与 MongoDB 服务器进行交互。

在 Mac OS X 中安装

假设您现在使用 Mac OS X 的 64 位版本,以下步骤详细说明了如何下载 MongoDB 的 64 位 OS X 二进制版本,解压它,配置并开始使用,还将教您如何作为守护程序运行 MongoDB。

首先,启动 Terminal (Applications>Utilities>Terminal)。在 Terminal 窗口,运行清单 5 中的命令。

清单 5. 在 Mac OS X上设置 MongoDB

				
$ cd ~
$ curl http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-1.6.4.tgz > mongo.tgz
$ tar xzf mongo.tgz
$ mv mongodb-osx-x86_64-1.8.1/ mongo
$ mkdir -p /data/db

MongoDB 现在设置完成并准备使用。在继续之前,最好把 MongoDB 添加到您的路径中,执行以下命令: $ nano ~/.bash_profile.

此文件可能还不存在。在这种情况下,添加以下行: export PATH={$PATH}:~/mongo/bin.

按 ctrl + O 保存文件,然后在提示符下按 Enter。再按 ctrl + X 退出。现在,用以下命令重新载入 bash 配置文件: $ source ~/.bash_profile.

您现在已经准备好启动 MongoDB。只需发出以下命令就可以启动: $ mongod.

这将作为前台进程启动 MongoDB 数据库服务器。如果您想作为后台守护程序启动 MongoDB ,发出以下命令: $ sudo mongod --fork --logpath /var/log/mongodb.log --logappend.

将要求您输入密码,在此提示下输入 Mac OS X 管理员密码。

无论您选择哪种方法启动 MongoDB,服务器现在都能运行。如果作为前台进程启动,您将需要一个单独的 Terminal 标签或窗口来启动客户端。要启动客户端,只需使用命令:$ mongo

将会看到清单 6 中的提示:

清单 6. 启动客户端

				
MongoDB shell version: 1.8.1
connecting to: test
>

在下一节中,您将学习如何使用 MongoDB shell 来创建数据库、集合、文档等。


回页首

MongoDB 使用入门

MongoDB 发行版包含一个 shell 应用程序,使您能够完全控制数据库。通过使用 shell,您可以使用服务器端 JavaScript 功能来创建和管理数据库、集合、文件和索引。这使快速启动和运行 MongoDB 变得容易。在本节中,您将学习如何启动 shell 并了解一些进行基本数据库存储和检索的命令。

MongoDB shell

MongoDB shell 应用程序包含在 MongoDB 发行版的 bin 文件夹中。在 Windows 系统中,它就是 mongo.exe 应用程序。在 Windows 资源管理器中,双击此程序即可启动 shell 。在基于 UNIX® 的操作系统中(包括 Mac OS X),您可通过在一个终端窗口(假使您按照以上说明将 MongoDB 目录加入到路径)执行 mongo 命令启动 MongoDB shell。

第一次启动 shell 时,您将看到清单 7 中消息。

清单 7. 启动 shell 时的消息

				
MongoDB shell version: 1.8.1
connecting to: test
>

您现在已连接到本地 MongoDB 服务器,尤其是“测试”服务器。在下一节中,您将学习如何创建数据库、文档和集合。如果您在某个阶段需要帮助,只需要在 Mongo shell 提示符下发出 “help” 命令。 图 1 显示了典型的帮助命令的输出。

图 1. Mongo shell help命令的输出

如果您想查看 MongoDB 函数背后的源代码,只需简单地在 shell 中输入函数的名称,它将会输出 JavaScript 源代码。例如,输入 connect 后按回车键,您将看到用于连接 MongoDB 数据库的源代码。

创建数据库、集合和文档

默认情况下,Mongo shell 连接到“测试”数据库。如果要切换到一个不同的数据库,使用 “use 数据库名” 命令。如果数据库不存在,在您将数据添加到数据库时,MongoDB 将会创建它。用以下命令切换到 “mymongo” 数据库: > use mymongo.

shell 将返回以下信息: switched to db mymongo.

这时,数据库仍未真正存在,因为它没有包含任何数据。在 MongoDB 中,数据以集合的形式存储。如果需要,您可以分割文档。下面创建一个文档并把它存储到一个名为 “colors” 的新集合中: > db.colors.save({name:"red",value:"FF0000"});.

通过查询数据库来验证文档已保存: > db.colors.find();.

您将看到类似于下面的响应(_id 属性是唯一标识符,与您的结果可能会不同): { "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "red", "value" : "FF0000" }.

MongoDB 中的文档以 BSON(二进制 JSON)形式存储。通过 Mongo shell,可以使用类似于 JSON 的语法插入数据,其中每个文档都是一个键-值对形式的对象。在这个例子中,我们创建一个具有两个属性的文档:namevalue,值分别为 redFF0000(标准红色的十六进制表示形式)。

您可能已经注意到,不需要预定义 colors 集合,当您使用存储功能插入一个条目时,文档将自动创建。

在这个例子中,您创建了一个非常简单的文档。然而,使用类似于 JSON 的语法可以创建更复杂的文档。考虑下面的 JSON 文档,它表示了一个订单或发票(参见 清单 8)。

清单 8. 创建一个简单的文档

				
{
    order_id: 109384,
    order_date: new Date("12/04/2010"),
    customer: {
        name: "Joe Bloggs",
        company: "XYZ Inc.",
        phone: "(555) 123-4567"
    },
    payment: {
        type: "Cash",
        amount: 4075.99,
        paid_in_full: true
    },
    items: [
        {
            sku: "ABC1200",
            description: "A sample product",
            quantity: 1,
            price_per_unit: 75.99,
        }, {
            sku: "XYZ3400",
            description: "An expensive product",
            quantity: 2,
            price_per_unit: 2000
        }
    ],
    cashier_id: 340582242
}

您可以看到,这些文档可以存储包括字符串、整数、浮点数、日期、对象、数组等的各种数据类型。在清单 8 中,订单条目直接嵌入在订单文档中,使得以后查询文档时检索信息快得多。

由于 MongoDB shell 使用 JavaScript,当您与数据库交互时,可以编写规则的 JavaScript 结构 。以清单 9为例,它创建一个字符文档集合,每个集合都包含字符的字符串表示形式及其关联的 ASCII 代码。

清单 9. 创建一个字符文档集合

				
> var chars = "abcdefghijklmnopqrstuvwxyz"
> for(var i =0; i<chars.length; i++) {    
... var char = chars.substr(i, 1);          
... var doc = {char:char, code: char.charCodeAt(0)};
... db.alphabet.save(doc);
... }

此循环将创建 26 个文档,代表字母表的每个小写字母,每个文档包含字符本身及其 ASCII 字符码。在下一节中,您将学习如何用不同方法检索数据。

检索数据

在最后一节中,您不仅会学习如何向 MongoDB 数据库中插入数据,而且会实际学习如何使用最基本的数据检索函数 find。我们以上一节结尾时创建的字母表集合为例,学习使用 find 命令: db.alphabet.find();

这将生成如清单 10 所示的响应。

清单 10. 生成响应

				
> db.alphabet.find()
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "char" : "e", "code" : 101 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f", "code" : 102 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g", "code" : 103 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h", "code" : 104 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i", "code" : 105 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec95"), "char" : "j", "code" : 106 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec96"), "char" : "k", "code" : 107 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec97"), "char" : "l", "code" : 108 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec98"), "char" : "m", "code" : 109 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec99"), "char" : "n", "code" : 110 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9a"), "char" : "o", "code" : 111 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9b"), "char" : "p", "code" : 112 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9c"), "char" : "q", "code" : 113 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9d"), "char" : "r", "code" : 114 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9e"), "char" : "s", "code" : 115 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9f"), "char" : "t", "code" : 116 }
has more
>

默认情况下,find() 函数会检索集合中的所有文档,但只显示前 20 个文档。给出命令 it 将检索剩余的 6 个文档(参见清单 11)。

清单 11. 检索剩余的 6 个文档

				
> it
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca0"), "char" : "u", "code" : 117 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca1"), "char" : "v", "code" : 118 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca2"), "char" : "w", "code" : 119 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca3"), "char" : "x", "code" : 120 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca4"), "char" : "y", "code" : 121 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca5"), "char" : "z", "code" : 122 }
>

find() 函数实际上向查询结果集返回了一个指针,在本例中是检索所有文件。如果没有分配一个变量或没有执行其他函数,它将在屏幕上默认打印一个样例结果集。要显示所有结果集,应执行以下命令: > db.alphabet.find().forEach(printjson);

这将打印结果集中的每条记录,而不是显示一个子集。接下来我们将了解更多有关使用指针和查询来筛选数据的方法。


回页首

查询数据

MongoDB 最强大的功能之一是它对 ad-hoc 查询的强大支持,其工作方式与传统关系数据库几乎一样,它筛选和返回 BSON 文档而不是表中的行。这种方法使它有别于其他文档存储,对于 SQL 开发人员来说,这一点很难掌握。利用 MongoDB ,相对复杂的 SQL 查询可以简单地转换为 JavaScript 函数调用。在本节中,您将学习可让您在 MongoDB 中查询数据的各种函数,以及如何建立索引来帮助优化查询,就像在 DB2、MySQL 或 Oracle 中一样。

基本查询

在上一节中,您学习了如何使用 find 函数来检索所有文档。find 函数接受一系列参数来筛选返回的结果。例如,在上面创建的字母表集合中,您能用以下命令找到 “char” 属性的值为 “q” 的任何记录: > db.alphabet.find({char: "o"});

这将返回以下响应: { "_id" : ObjectId("4cfa4adf528bad4e29beec9a"), "char" : "o", "code" : 111 }

如果您想要返回编码小于或等于 100 的所有字符,可以使用以下命令: > db.alphabet.find({code:{$lte:100}});.

这将返回清单 12 中的结果,与您期望的一致。

清单 12. 结果

				
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }

MongoDB 支持各种条件运算符,包括:

  • $lt(小于)
  • $lte(小于等于)
  • $gt(大于)
  • $gte(大于等于)
  • $all(匹配数组中的所有值)
  • $exists(检查字段是否存在)
  • $mod(模数)
  • $ne(不等)
  • $in(匹配数组一个或多个值)
  • $nin(匹配数组中的零值)
  • $or(匹配一个或另一个查询)
  • $nor(不匹配查询)
  • $size(匹配具有预定数量元素的任何数组)
  • $type(匹配具有指定 BSON 数据类型的值)
  • $not (不等于)

有关所有这些运算符的详细信息,请参阅 MongoDB 文档(参见参考资料中的链接)。

您可以使用 find 函数中的第二个参数来限制查询返回的字段。例如,下面的查询只返回所有文档中编码值范围在 102 至 105 之间的 char 属性: > db.alphabet.find({code:{$in:[102,103,104,105]}}, {char: 1});.

这将产生 清单 13 中的结果。

清单 13. 结果

				
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i" }

在下一节中,您将学习如何创建索引来加速查询。

索引

MongoDB 索引与关系数据库中的索引十分相似。您可以基于任何属性建立索引。此外,索引后的字段可以是任何数据类型,包括一个对象或数组。与 RDBMS 索引相似,可以使用多个属性创建复合索引,也可创建唯一索引,确保不存在重复的值。

要创建一个基本索引,使用 ensureIndex 函数。下面使用字母表集合中的 codechar 属性创建一个索引。(参见清单 14)。

清单 14. 创建索引

				
> db.alphabet.ensureIndex({code: 1});
> db.alphabet.ensureIndex({char: 1});

可以使用 dropIndex 和 dropIndexes 函数删除索引。可参阅 MongoDB 文档获得更多信息。

排序

要对结果集进行排序,可以对指针应用 sort 函数。字母表集合已经基于 code 和 char 属性的升序排序,下面按 code 属性的升序排序,返回一个子集: > db.alphabet.find({code: {$gte: 118}}).sort({code: 0});

这将返回清单 15 中的结果。

清单 15. 结果

				
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca5"), "char" : "z", "code" : 122 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca4"), "char" : "y", "code" : 121 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca3"), "char" : "x", "code" : 120 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca2"), "char" : "w", "code" : 119 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca1"), "char" : "v", "code" : 118 }

如果在上一条命令中为 sort 函数提供参数 {code: 1} ,它将会以升序对结果排序。为了确保高效的查询,一定要为排序的数据属性添加索引。


回页首

使用 skip 和 limit 分页结果

通常在处理数据结果集时,一次只想检索一个子集,也许是在网页上提供分页结果。在 MySQL 中,您通常使用 LIMIT 关键字来实现。您在 MongoDB 中只需使用 skip 和 limit 函数即可实现这一功能。要返回字母表集合中的前 5 个文档,可执行以下操作: > db.alphabet.find().limit(5);

这将返回清单 16 中的结果。

清单 16. 结果

				
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "char" : "e", "code" : 101 }

要获得下一页,使用以下命令: > db.alphabet.find().skip(5).limit(5);

清单 17 所示,这将获取接下来的 5 条记录。

清单 17. 获取接下来的 5 条记录

				
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f", "code" : 102 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g", "code" : 103 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h", "code" : 104 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i", "code" : 105 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec95"), "char" : "j", "code" : 106 }

回页首

分组函数和聚合

MongoDB 的查询引擎也使得对数据应用聚合和分组函数变得非常简单。这类似于 SQL 中的相应功能。可以说,应用最广泛的函数是 count() 函数:> db.alphabet.find().count();

这将返回 26。您可以简单对筛选出的查询结果进行计数: > db.alphabet.find({code: {$gte: 105}}).count();

以上命令将返回 18。

另一个有用的聚合函数是 distinct。利用它可返回针对某个属性的一组不同的值。由于所有数据都是唯一的,因此字母表集合不是一个合适的例子。我们向本文开头创建的 colors 集合中添加一些记录(参见清单 18)。

清单 18. 向 color 集合中添加记录

				
> db.colors.save({name:"white",value:"FFFFFF"});
> db.colors.save({name:"red",value:"FF0000"});  
> db.colors.find();

假定您没有删除 colors 集合,您将看到 清单 19 中的响应。

清单 19. 响应

				
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "red", "value" : "FF0000" }
{ "_id" : ObjectId("4cfa5830528bad4e29beeca8"), "name" : "white", "value" : "FFFFFF" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

您可以看到,在这个集合中明显有两个 red 文档。现在使用 distinct 函数从此集合中获得一组唯一的 name 属性: > db.colors.distinct("name");

这将返回: [ "red", "white" ]

值得注意的是,您在执行其他查询函数时不能在指针和结果集上执行 distinct 函数,而应直接在集合上执行。还应注意,它返回的不是一组文档,而是一组值。

MongoDB 还为执行类似于 SQL 中的 GROUP BY 表达式的操作提供了 group 函数。group 函数是一个异常复杂的函数,所以我在这里只给出一个简短的示例。例如,我们要按 name 值来分组计算文档数。在 SQL 中,可以定义表达式为 SELECT name, COUNT(*) FROM colors GROUP BY name;

要在 MongoDB 中执行此查询,需要使用清单 20 中的命令。

清单 20. 使用 group 函数

				
> db.colors.group(
... {key: {name: true},
... cond: {},
... initial: {count: 0},                                  
... reduce: function(doc, out) { out.count++; }
... });

这将产生在清单 21 中的结果。

清单 21. 结果

				
[
    {
        "name" : "red",
        "count" : 2
    },
    {
        "name" : "white",
        "count" : 1
    }
]

如果需要执行高级聚合或使用大型数据集,MongoDB 还包含一个 map/reduce 实现,让您能够完成这一任务。上面介绍的 group 函数在分片的 MongoDB 安装中无法工作,所以如果您要使用分片,一定要使用 map/reduce 来替代 group 函数。

更新现有数据

在 MongoDB shell 中,更新文档非常容易。在前面创建的 colors 集合中,有两条 red 记录。要从记录中取出一个并将它更改为 black,且值属性为 000000 (黑色的十六进制值)。首先,可以使用 findOne 函数来检索值为 red 的单个项目,根据需要更改其属性,并将文档存储到数据库中。

获取名称为 red 的单一文档并把它存储在 blackDoc 变量中: > var blackDoc = db.colors.findOne({name: "red"});

接下来,使用点表示法修改文档的属性(参见清单 22)。

清单 22. 修改文档属性

				
> blackDoc.name = "black";
> blackDoc.value = "000000";

在保存之前,检查文档是否正确(它应该有 _id 属性,否则只是插入了一条新记录而不是覆盖 red 记录): > printjson(blackDoc);

如果返回结果类似于清单 23,则表示您准备好了。

清单 23. 结果

				
{
    "_id" : ObjectId("4cfa43ff528bad4e29beec57"),
    "name" : "black",
    "value" : "000000"
}

最后,使用 save 函数将文档保存回数据库中的 colors 集合: > db.colors.save(blackDoc);

现在可以使用 find 函数来确保集合是正确的: > db.colors.find();

这将返回类似于清单 24 的结果。如果您有 4 条记录,您就错了。

清单 24. 结果

				
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "black", "value" : "000000" }
{ "_id" : ObjectId("4cfa5830528bad4e29beeca8"), "name" : "white", "value" : "FFFFFF" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

除了 Mongo shell 之外,您可以在应用程序中使用 update 函数来将更改应用到现有数据。有关 update 函数的更多信息,请参阅 MongoDB 文档。

删除数据

要删除 MongoDB 中的数据,可使用 remove 函数。请注意这适用于 MongoDB shell 程序,某些驱动程序可能使用 delete 函数或者没有。如有必要,可查阅某个具体实现的相关文档。

remove 函数与 find 函数工作方式类似。要删除 colors 集合中与名称 white 相匹配的任何文档,可使用以下命令: > db.colors.remove({name:"white"});

然后,可以检查此文档是否已删除: > db.colors.find();

如果正确,您将只会看见两个文档(参见清单 25)。

清单 25. 删除数据

				
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "black", "value" : "000000" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

要删除集合中的所有文档,只需在命令中省略筛选器,类似如下: > db.colors.remove();

现在如果您试图使用 find 函数,将得不到响应,表示一个空的结果集: > db.colors.find();

如果文档存储在变量中,也可以将此文档传送给 remove 函数以删除它,但这么做非常低效。最好找到这个文档的 _id 属性并把它传送给 remove 函数。

要删除一个集合,使用以下命令: > db.colors.drop();

这将返回以下结果: true

现在可以使用 show collections 命令检查集合确实已被删除。这将产生清单 26 中的输出。

清单 26. 使用 show collections 命令

				
alphabet
system.indexes

最后,如果您想要删除整个数据库,执行如下命令:> db.dropDatabase();

这将删除当前选定的数据库。您将看到以下输出: { "dropped" : "mymongo", "ok" : 1 }.

可以使用 show dbs 命令获得可用数据库列表。mymongo 将不会出现在这个列表中。


回页首

工具及其他特性

MongoDB 包含一系列用于管理数据库的有用工具。无论是报表还是备份,它都提供了各种方式来导入和导出数据。在本节中,您将了解如何以 JSON 格式导入和导出文件,以及如何创建用于高效恢复的热备份文件。您还将学习如何使用 map/reduce 函数作为 Mongo 用于复杂数据聚合的常规查询函数的一种替代方式。

导入和导出数据

MongoDB 的 bin 目录包含了一系列工具,可用于以各种格式导入和导出数据。 mongoimport 工具允许您提供一个文件,其中每行包含一个 JSON 、CSV 或 TSV 格式的文档,并将这些文档插入 MongoDB 数据库。由于 MongoDB 使用 BSON 格式,如果希望利用在常规 JSON 中无法使用的 BSON 附加数据类型,在导入 JSON 文档时需要提供一些说明信息。

mongoexport 工具允许您生成一个文件输出,其中 MongoDB 数据库中的每个文档都以 JSON 或 CSV 格式表示。这对于生成报表非常有用,因为应用程序接受 JSON 或 CSV 数据作为输入。要生成一个 CSV 文件,需要按输出文件中显示的顺序提供字段。

备份和恢复数据库

当需要从 MongoDB 中取出数据以用于其他应用程序或从其他使用 JSON 或 CSV 数据的应用程序中导入数据时,mongoimport 和 mongoexport 工具非常有用。然而,这些工具不能用于获得定期备份或 MongoDB 数据库,也不能用于恢复 MongoDB 数据库。因为 MongoDB 使用 BSON 而不是 JSON 或 CSV ,从这些格式中导入数据时很难保留数据类型。

为了提供适当的备份和恢复功能,MongoDB 提供了两个工具:mongodump 和 mongorestore。 mongodump 用于生成数据库的二进制文件备份,mongorestore 用于读取此文件并使用它恢复数据库,并根据需要自动创建索引(除非已将 system.indexes.bson 文件从备份目录中删除)。


回页首

管理工具

MongoDB 还提供了一个基于 Web 的诊断接口,在默认 MongoDB 配置上从 http://localhost:28017/ 可以获得。这个屏幕类似于图 2

图 2. MongoDB 诊断

为了获得其他管理信息,也可以在 MongoDB shell 中运行以下命令:

  • db.serverStatus();
  • db.stats();

如果 MongoDB 服务器崩溃,应修复数据库以检查错误并执行一些数据精简。可以通过在操作系统命令行中运行 mongod --repair 进行修复,或选择从 MongoDB shell 运行 db.repairDatabase() 命令。后一个命令在每个数据库的级别上运行,所以您需要针对服务器上的每个数据库都运行此命令。

您也可以使用 validate 函数验证集合数据。如果拥有一个名为 contacts 的集合,可以用 db.contacts.validate() 命令验证此集合。

MongoDB 有很多其他特性可让数据库管理员更轻松,包括各种各样的第三方管理工具和可用的接口。请参阅 MongoDB 文档以获得更多信息。

map/reduce 函数

如果您以前使用过 CouchDB 数据库,可能熟悉 map/reduce 函数,因为视图引擎默认使用 map/reduce 函数来筛选和聚合数据。在 MongoDB 中,情况不是这样的,简单的查询和筛选(甚至聚合)不依靠 map/reduce 来完成。不过,MongoDB 确实为聚合大型数据集的应用提供了 map/reduce 实现。

map/reduce 这一主题可能需要一整篇文章来描述。有关 MongoDB 实现的详细信息,请参阅 MongoDB 文档。(参见参考资料中的链接)。


回页首

扩展 MongoDB

键/值存储和面向文档数据库最近流行的主要原因是它们占用资源少及其高度可扩展性。为了发挥这些优势,MongoDB 引入了分片和复制的概念,您将在本节中学习。此外,您还将学习如何在 MongoDB 中使用 GridFS 存储大文件。最后,您将了解如何对查询进行分析以优化数据库的性能。

分片

数据库基础架构的一个重要部分就是确保其良好的可扩展性。MongoDB 实现采用一种自动分片机制来确保其横向扩展,这使得 MongoDB 配置可扩展至数千个节点,具有自动负载平衡、无单点故障和自动故障转移功能,向 MongoDB 集群添加新机器也非常简单。

MongoDB 的自动分片特性的好处是它使得从单一服务器转向分片集群变得非常容易,通过无需或很少需要对所需的程序代码进行改动。有关自动分片的工作原理及如何实现它的详细信息,请参阅 MongoDB 文档。

复制

为了实现故障转移和冗余,MongoDB 在主从配置中提供了复制特性(类似于 MySQL),从而确保节点之间的高度一致性。也就是说,MongoDB 可以在任何时候使用副本集将某个节点定义为主节点,在故障时另一节点担负起主节点的任务。

与 CouchDB 使用复制作为扩展机制的思路不同,MongoDB 主要使用复制来确保高度可用性,方法是使用从属节点作为冗余副本。

有关 MongoDB 复制的更多信息,请参阅文档(参见参考资料中的链接)。

使用 GridFS 的大文件存储

MongoDB 数据库以 BSON 文档存储数据。BSON 文档的最大大小是 4MB,这不适合存储大文件和对象。MongoDB 通过将文件划分为多个文档之间的较小块,使用 GridFS 规范来存储大文件。

标准 MongoDB 发行版包含将 GridFS 文件添加到本地文件系统以及从本地文件系统检索 GridFS 文件的命令行工具。另外,所有官方 MongoDB API 驱动程序都包含对 GridFS 的支持。有关详细信息,请参阅 MongoDB 文档(参见参考资料)。


回页首

结束语

在本文中,您学习了 MongoDB 数据库管理系统,以及它成为 DBMS 市场受欢迎的 NoSQL 中成长最快的可选产品的原因。您学习了为何要选择优于传统 RDBMS 的面向文档数据库,以及 MongoDB 提供的各种强大功能。还学习了如何安装和使用 MongoDB 来存储和检索数据,以及它提供的各种工具和可扩展性选项。

参考资料

学习

获得产品和技术

讨论

from:http://www.ibm.com/developerworks/cn/opensource/os-mongodb4/

ubuntu安装启动redis2.4.15

1、下载安装

cd /tmp
tar -zxf redis-2.4.15.tar.gz
cd redis-2.4.15
make
sudo make install

如果是新安装的操作系统,在make的时候会报找不到gcc命令,那么先执行

sudo apt-get install build-essential

这时Redis 的可执行文件被放到了/usr/local/bin

2、下载配置文件和init启动脚本:

sudo mv redis-server /etc/init.d/redis-server
sudo chmod +x /etc/init.d/redis-server
sudo mv redis.conf /etc/redis.conf

3、初始化用户和日志路径

第一次启动Redis前,建议为Redis单独建立一个用户,并新建data和日志文件夹

sudo useradd redis
sudo mkdir -p /var/lib/redis
sudo mkdir -p /var/log/redis
sudo chown redis.redis /var/lib/redis
sudo chown redis.redis /var/log/redis

4、设置开机自动启动,关机自动关闭

sudo update-rc.d redis-server defaults

5、启动Redis:

sudo /etc/init.d/redis-server start

 在启动时,因默认的配置启用虚拟内存支持会报错。把vi命令修改配置项vm-enabled no,然后再启动。

6、启动client客户端连接:

$ redis-cli
redis> set foo bar
OK
redis> get foo
"bar"