MongoDB使用说明手册

目录

1          MongoDB简介... 1

1.1            功能特点... 1

1.2            适用范围... 1

2           window平台安装 MongoDB.. 1

2.1            下载地址... 1

2.2            安装方法... 2

2.3             MongoDB后台管理 Shell. 3

3           Linux平台安装 MongoDB.. 4

3.1             创建数据库目录... 4

3.2             命令行中运行 MongoDB 服务... 4

3.3             MongoDB后台管理 Shell. 4

3.4             MongoDb web 用户界面... 5

4          MongoDB基础知识... 5

4.1           基本命令... 5

4.1.1. 启动mongodb. 5

4.1.2. 停止mongodb. 6

4.2    SQL语法... 6

4.2.1. 基本操作.. 6

4.2.2. 数据集()操作.. 6

4.3    MongoDB基本概念... 7

4.3.1. 数据库.. 8

4.3.2. 文档.. 9

4.3.3. 集合.. 9

4.3.4. 元数据.. 10

4.3.5. MongoDB 数据类型.. 11

4.4    MongoDB连接... 11

4.4.1. 启动 MongoDB服务.. 11

4.4.2. 通过shell连接MongoDB服务.. 12

4.4.3. MongoDB连接命令格式.. 12

4.4.4. 更多连接实例.. 12

4.4.5. 参数选项说明.. 13

4.5     MongoDB创建数据库... 14

4.5.1. 语法.. 14

4.5.2. 实例.. 14

4.6    MongoDB删除数据库... 14

4.6.1. 语法.. 14

4.6.2. 实例.. 14

4.7    MongoDB插入文档... 15

4.7.1. 插入文档.. 15

4.7.2. 实例.. 15

4.8    MongoDB更新文档... 16

4.8.1. update() 方法.. 16

4.8.2. 实例.. 16

4.8.3. save() 方法.. 17

4.8.4. 实例.. 18

4.8.5. 更多实例.. 18

4.9    MongoDB删除文档... 19

4.9.1.       语法.. 19

4.9.2.       实例.. 19

4.10       MongoDB查找文档... 20

4.10.1.            语法... 20

4.10.2.            MongoDB RDBMS Where 语句比较... 20

4.10.3.            MongoDB AND 条件... 21

4.10.4.            MongoDB OR 条件... 21

4.10.5.            AND OR 联合使用... 21

4.11        MongoDB条件操作符... 22

4.11.1.            描述... 22

4.11.2.            MongoDB (>) 大于操作符 - $gt 23

4.11.3.            MongoDB>=)大于等于操作符 - $gte. 23

4.11.4.            MongoDB (<) 小于操作符 - $lt 23

4.11.5.            MongoDB (<=) 小于操作符 - $lte. 24

4.11.6.            MongoDB 使用 (<) (>) 查询 - $lt $gt 24

4.12        MongoDB  $type 操作符... 24

4.13        MongoDB  LimitSkip方法... 26

4.14        MongoDB排序... 27

4.15        MongoDB索引... 27

4.16        MongoDB聚合... 28

4.17        MongoDB复制... 29

4.18        MongoDB分片... 30

4.19        MongoDB备份(mongodump)与恢复(mongorerstore). 32

4.20        MongoDB监控... 33

5          JAVA操作MongoDB.. 35

6          MongoDB PHP 扩展... 41

7          MongoDB PHP.. 42

8          MongoDB 高级... 45

8.1     MongoDB 关系... 45

8.2     MongoDB 数据库引用... 47

8.3     MongoDB 覆盖索引查询... 48

8.4     MongoDB 查询分析... 49

8.5     MongoDB 原子操作... 50

8.6     MongoDB 高级索引... 52

8.7     MongoDB 索引限制... 53

8.8     MongoDB ObjectId.. 54

8.9     MongoDB Map Reduce. 55

8.10 MongoDB 全文检索.. 56

8.11 MongoDB 正则表达式.. 58

8.12 MongoDB 管理工具: Rockmongo. 59

8.13 MongoDB GridFS. 60

8.14 MongoDB 固定集合(Capped Collections.. 61

8.15 MongoDB 自动增长.. 61

 

第一章MongoDB简介

1.1      功能特点

官方网址:http://www.mongodb.org/

MongoDB是一个基于分布式文件存储的数据库开源项目。由C++语言编写,旨在为WEB应用提供可护展的高性能数据存储解决方案。

它的特点是可扩展高性能易使用模式自由,存储数据非常方便等,主要功能特性有:

u  面向文档存储:(JSON数据模式简单而强大)

u  高效的传统存储方式:支持二进制数据及大型对象(如照片和视频)。

u  复制及自动故障转移:Mongo数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。

u  Auto-Sharding自动分片支持云级扩展性(处于早期alpha阶段):自动分片功能支持水平的数据库集群,可动态添加额外的机器。

u  动态查询:它支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。

u  全索引支持:包括文档内嵌对象及数组。Mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。

u  支持RUBYPYTHONJAVAC++PHP等多种语言

1.2  适用范围

适用场景:

u  适合实时的插入,更新与查询,并具备应用程序实时数据存储所需的复制及高度伸缩性。

u  适合作为信息基础设施的持久化缓存层。

u  适合由数十或数百台服务器组成的数据库。因为Mongo已经包含对MapReduce引擎的内置支持。

u  MongoBSON数据格式非常适合文档化格式的存储及查询。

 

不适用场景:

u  高度事务性的系统。

u  传统的商业智能应用。

u  级为复杂的SQL查询。

 

2window平台安装 MongoDB

2.1 下载地址

MongoDB提供了可用于32位和64位系统的预编译二进制包,你可以从MongoDB官网下载安装,MongoDB预编译二进制包下载地址:http://www.mongodb.org/downloads

注意:在 MongoDB2.2 版本后已经不再支持 Windows XP 系统。

 

http://www.runoob.com/wp-content/uploads/2013/10/mongodb-download.jpg

·        MongoDB for Windows 64-bit 适合 64 位的 Windows Server 2008 R2, Windows 7 , 及最新版本的 Window 系统。

·        MongoDB for Windows 32-bit 适合 32 位的 Window 系统及最新的 Windows Vista 32 位系统上 MongoDB 的数据库最大为 2GB

·        MongoDB for Windows 64-bit Legacy 适合 64 位的 Windows Vista, Windows Server 2003, Windows Server 2008

根据你的系统下载 32 位或 64 位的 .msi 文件,下载后双击该文件,按操作提示安装即可。

安装过程中,你可以通过点击 "Custom(自定义)" 按钮来设置你的安装目录。

 

http://www.runoob.com/wp-content/uploads/2013/10/win-install1.jpg

 

http://www.runoob.com/wp-content/uploads/2013/10/win-install2.jpg

 

2.2 安装方法

通过mongod –install命令把mongodb注册成为window service

1)      创建数据库存储目录;例如:d:\data\db

2)      通过命令行执行:

mongod --bind_ip 127.0.0.1 --logpath d:\data\logs --logappend --dbpath d:\data\db

--directoryperdb –install

 

下表为mongodb启动的参数说明:

 

参数

描述

--bind_ip

绑定服务IP,若绑定127.0.0.1,则只能本机访问,不指定默认本地所有IP

--logpath

MongoDB日志文件,注意是指定文件不是目录

--logappend

使用追加的方式写日志

--dbpath

指定数据库路径

--port

指定服务端口号,默认端口27017

--serviceName

指定服务名称

--serviceDisplayNam

指定服务名称,有多个mongodb服务时执行。

--install

指定作为一个Windows服务安装。

 

 

注:mongodb安装成服务,装该服务绑定到IP127.0.0.1,日志文件为d:\data\logs,以及添加方式记录。数据目录为d:\data\db。并且每个数据库将储存在一个单独的目录(--directoryperdb)】

 

安装成功后,如下图:

 

 

3)      启动服务后,尝试是否可用,通过命令行进入%MONGODB_HOME%\bin下执行mongo.exe命令后出现如下图所示信息表示连接成功:

 

 

2.3 MongoDB后台管理 Shell

如果你需要进入MongoDB后台管理,你需要先打开mongodb装目录的下的bin目录,然后执行mongo.exe文件,MongoDB ShellMongoDB自带的交互式Javascript shell,用来对MongoDB进行操作和管理的交互式环境。

 

当你进入mongoDB后台后,它默认会链接到 test 文档(数据库):

 

> mongo

MongoDB shell version: 3.0.6

connecting to: test

……

 

由于它是一个JavaScript shell,您可以运行一些简单的算术运算:

 

> 2 + 2

4

> 

db 命令用于查看当前操作的文档(数据库):

 

> db

test

> 

插入一些简单的记录并查找它:

 

> db.runoob.insert({x:10})

WriteResult({ "nInserted" : 1 })

> db.runoob.find()

{ "_id" : ObjectId("5604ff74a274a611b0c990aa"), "x" : 10 }

> 

第一个命令将数字 10 插入到 runoob 集合的 x 字段中。

 

3Linux平台安装 MongoDB

下载完安装包,并解压 tgz(以下演示的是 64 Linux上的安装)

 

curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.6.tgz    # 下载
tar -zxvf mongodb-linux-x86_64-3.0.6.tgz                                   # 解压
 
mv  mongodb-linux-x86_64-3.0.6/ /usr/local/mongodb                         # 将解压包拷贝到指定目录

MongoDB 的可执行文件位于 bin 目录下,所以可以将其添加到 PATH 路径中:

 

export PATH=<mongodb-install-directory>/bin:$PATH

<mongodb-install-directory> 为你 MongoDB 的安装路径。如本文的 /usr/local/mongodb 

 


3.1创建数据库目录

MongoDB的数据存储在data目录的db目录下,但是这个目录在安装过程不会自动创建,所以你需要手动创建data目录,并在data目录中创建db目录。

以下实例中我们将data目录创建于根目录下(/)

注意:/data/db MongoDB 默认的启动的数据库路径(--dbpath)

 

mkdir -p /data/db

 


3.2命令行中运行 MongoDB 服务

你可以再命令行中执行mongo安装目录中的bin目录执行mongod命令来启动mongdb服务。

 

注意:如果你的数据库目录不是/data/db,可以通过 --dbpath 来指定。

 
$ ./mongod
 
2015-09-25T16:39:50.549+0800 I JOURNAL  [initandlisten] journal dir=/data/db/journal
2015-09-25T16:39:50.550+0800 I JOURNAL  [initandlisten] recover : no journal files present, no recovery needed
2015-09-25T16:39:50.869+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 3.16
2015-09-25T16:39:51.206+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 3.52
2015-09-25T16:39:52.775+0800 I JOURNAL  [initandlisten] preallocateIsFaster=true 7.7

 


3.3 MongoDB后台管理 Shell

如果你需要进入MongoDB后台管理,你需要先打开mongodb装目录的下的bin目录,然后执行mongo命令文件。

MongoDB ShellMongoDB自带的交互式Javascript shell,用来对MongoDB进行操作和管理的交互式环境。

当你进入mongoDB后台后,它默认会链接到 test 文档(数据库):

 

$ cd /usr/local/mongodb/bin
$ ./mongo
MongoDB shell version: 3.0.6
connecting to: test
Welcome to the MongoDB shell.
……

由于它是一个JavaScript shell,您可以运行一些简单的算术运算:

 

> 2+2
4
> 3+6
9

现在让我们插入一些简单的数据,并对插入的数据进行检索:

 

> db.runoob.insert({x:10})
WriteResult({ "nInserted" : 1 })
> db.runoob.find()
{ "_id" : ObjectId("5604ff74a274a611b0c990aa"), "x" : 10 }
> 

第一个命令将数字 10 插入到 runoob 集合的 x 字段中。

 


3.4 MongoDb web 用户界面

MongoDB 提供了简单的 HTTP 用户界面。 如果你想启用该功能,需要在启动的时候指定参数 --rest

 

$ ./mongod --dbpath=/data/db --rest

 

MongoDB Web 界面访问端口比服务的端口多1000

如果你的MongoDB运行端口使用默认的27017,你可以在端口号为28017访问web用户界面,即地址为:http://localhost:28017

 

http://www.runoob.com/wp-content/uploads/2013/10/mongodb-web.jpg

 

4MongoDB基础知识

4.1基本命令

4.1.1启动mongodb

run 直接启动:

例如:mongod run

--dbpath 指定存储目录启动:

例如:mongod dbpath = d:\ db

--port 指定端口启动:(默认端口是:27017)

例如:mongod --port 12345

4.1.2停止mongodb

在窗口模式中,可以直接使用Ctrl+C停止服务。

4.2 SQL语法

4.2.1 基本操作

db.addUser(username,password)  添加用户

db.auth(usrename,password)     设置数据库连接验证

db.cloneDataBase(fromhost)     从目标服务器克隆一个数据库

db.commandHelp(name)           returns the help for the command

db.copyDatabase(fromdb,todb,fromhost)  复制数据库fromdb---源数据库名称,todb---目标数据库名称,fromhost---源数据库服务器地址

db.createCollection(name,{size:3333,capped:333,max:88888})  创建一个数据集,相当于一个表

db.currentOp()                 取消当前库的当前操作

db.dropDataBase()              删除当前数据库

db.eval(func,args)             run code server-side

db.getCollection(cname)        取得一个数据集合,同用法:db['cname'] or

db.getCollenctionNames()       取得所有数据集合的名称列表

db.getLastError()              返回最后一个错误的提示消息

db.getLastErrorObj()           返回最后一个错误的对象

db.getMongo()                  取得当前服务器的连接对象get the server

db.getMondo().setSlaveOk()     allow this connection to read from then nonmaster membr of a replica pair

db.getName()                   返回当操作数据库的名称

db.getPrevError()              返回上一个错误对象

db.getProfilingLevel()        

db.getReplicationInfo()        获得重复的数据

db.getSisterDB(name)           get the db at the same server as this onew

db.killOp()                    停止(杀死)在当前库的当前操作

db.printCollectionStats()      返回当前库的数据集状态

db.printReplicationInfo()

db.printSlaveReplicationInfo()

db.printShardingStatus()       返回当前数据库是否为共享数据库

db.removeUser(username)        删除用户

db.repairDatabase()            修复当前数据库

db.resetError()               

db.runCommand(cmdObj)          run a database command. if cmdObj is a string, turns it into {cmdObj:1}

db.setProfilingLevel(level)    0=off,1=slow,2=all

db.shutdownServer()            关闭当前服务程序

db.version()                   返回当前程序的版本信息

4.2.2数据集(表)操作

db.test.find({id:10})          返回test数据集ID=10的数据集

db.test.find({id:10}).count()  返回test数据集ID=10的数据总数

db.test.find({id:10}).limit(2) 返回test数据集ID=10的数据集从第二条开始的数据集

db.test.find({id:10}).skip(8)  返回test数据集ID=10的数据集从0到第八条的数据集

db.test.find({id:10}).limit(2).skip(8)  返回test数据集ID=1=的数据集从第二条到第八条的数据

db.test.find({id:10}).sort()   返回test数据集ID=10的排序数据集

db.test.findOne([query])       返回符合条件的一条数据

db.test.getDB()                返回此数据集所属的数据库名称

db.test.getIndexes()           返回些数据集的索引信息

db.test.group({key:...,initial:...,reduce:...[,cond:...]})

db.test.mapReduce(mayFunction,reduceFunction,<optional params>)

db.test.remove(query)                      在数据集中删除一条数据

db.test.renameCollection(newName)          重命名些数据集名称

db.test.save(obj)                          往数据集中插入一条数据

db.test.stats()                            返回此数据集的状态

db.test.storageSize()                      返回此数据集的存储大小

db.test.totalIndexSize()                   返回此数据集的索引文件大小

db.test.totalSize()                        返回些数据集的总大小

db.test.update(query,object[,upsert_bool]) 在此数据集中更新一条数据                        

db.test.validate()                         验证此数据集                                       

db.test.getShardVersion()                  返回数据集共享版本号

 

MongoDB语法与现有关系型数据库SQL语法比较

MongoDB语法                                   MySql语法

db.test.find({'name':'foobar'}) <==> select * from test where name='foobar'

db.test.find()                            <==> select * from test

db.test.find({'ID':10}).count() <==> select count(*) from test where ID=10

db.test.find().skip(10).limit(20) <==> select * from test limit 10,20

db.test.find({'ID':{$in:[25,35,45]}}) <==> select * from test where ID in (25,35,45)

db.test.find().sort({'ID':-1})  <==> select * from test order by ID desc

db.test.distinct('name',{'ID':{$lt:20}})  <==> select distinct(name) from test where ID<20

 

db.test.group({key:{'name':true},cond:{'name':'foo'},reduce:function(obj,prev){prev.msum+=obj.marks;},initial:{msum:0}})  <==> select name,sum(marks) from test group by name

 

db.test.find('this.ID<20',{name:1})  <==> select name from test where ID<20

 

db.test.insert({'name':'foobar','age':25})<==>insert into test ('name','age') values('foobar',25)

 

db.test.remove({})                        <==> delete * from test

db.test.remove({'age':20})            <==> delete test where age=20

db.test.remove({'age':{$lt:20}})   <==> elete test where age<20

db.test.remove({'age':{$lte:20}})  <==> delete test where age<=20

db.test.remove({'age':{$gt:20}})  <==> delete test where age>20

db.test.remove({'age':{$gte:20}}) <==> delete test where age>=20

db.test.remove({'age':{$ne:20}})  <==> delete test where age!=20

 

db.test.update({'name':'foobar'},{$set:{'age':36}}) <==> update test set age=36 where name='foobar'

db.test.update({'name':'foobar'},{$inc:{'age':3}}) <==> update test set age=age+3 where name='foobar'

 

4.3 MongoDB基本概念

不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是文档、集合、数据库,下面我们挨个介绍。

下表将帮助您更容易理解Mongo中的一些概念:

 

SQL术语/概念

MongoDB术语/概念

解释/说明

database

database

数据库

table

collection

数据库表/集合

row

document

数据记录行/文档

column

field

数据字段/

index

index

索引

table joins

 

表连接,MongoDB不支持

primary key

primary key

主键,MongoDB自动将_id字段设置为主键

通过下图实例,我们也可以更直观的的了解Mongo中的一些概念:

 

http://www.runoob.com/wp-content/uploads/2013/10/Figure-1-Mapping-Table-to-Collection-1.png


4.3.1数据库

一个mongodb中可以建立多个数据库。

MongoDB的默认数据库为"db",该数据库存储在data目录中。

MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

"show dbs" 命令可以显示所有数据的列表。

 

$ ./mongo
MongoDB shell version: 3.0.6
connecting to: test
> show dbsshow dbs
local  0.078GB
test   0.078GB
> 

执行 "db" 命令可以显示当前数据库对象或集合。

 

$ ./mongo
MongoDB shell version: 3.0.6
connecting to: test
> db
test
> 

运行"use"命令,可以连接到一个指定的数据库。

 

> use local
switched to db local
> db
local
> 

以上实例命令中,"local" 是你要链接的数据库。

在下一个章节我们将详细讲解MongoDB中命令的使用。

数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串。

 

·        不能是空字符串("")

·        不得含有' '(空格).$/\\0 (空宇符)

·        应全部小写。

·        最多64字节。

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。

 

·        admin 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。

 

·        local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合

 

 

·        config: Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息

 


4.3.2 文档

文档是mongodb中的最核心的概念,是其核心单元,我们可以将文档类比成关系型数据库中的每一行数据。

多个键及其关联的值有序的放置在一起就是文档。MongoDB使用了BSON这种结构来存储数据和网络数据交换。

BSON数据可以理解为在JSON的基础上添加了一些json中没有的数据类型。

如果我们会JSON,那么BSON我们就已经掌握了一半了,至于新添加的数据类型后面我会介绍。

文档例子如下:

 

{ site : "runoob.com" }

 

通常,"object(对象)" 术语是指一个文档。

文档类似于一个RDBMS的记录。

需要注意的是:

 

1.      文档中的键/值对是有序的。

2.      文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)

3.      MongoDB区分类型和大小写。

4.      MongoDB的文档不能有重复的键。

5.      文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:

 

·        键不能含有\0 (空字符)。这个字符用来表示键的结尾。

·        .$有特别的意义,只有在特定环境下才能使用。

·        以下划线"_"开头的键是保留的(不是严格要求的)


4.3.3集合

集合就是一组文档的组合。如果将文档类比成数据库中的行,那么集合就可以类比成数据库的表。

mongodb中的集合是无模式的,也就是说集合中存储的文档的结构可以是不同的,比如下面的两个文档可以同时存入到一个集合中:

 

{"name":"mengxiangyue"}
{"Name":"mengxiangyue","sex":"nan"}

 

当第一个文档插入时,集合就会被创建。

 

4.3.3.1合法的集合名

·        集合名不能是空字符串""

·        集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。

·        集合名不能以"system."开头,这是为系统集合保留的前缀。

·        用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。 

如下实例:

 

db.col.findOne()

4.3.3.2 capped collections

Capped collections 就是固定大小的collection

它有很高的性能以及队列过期的特性(过期按照插入的顺序). 有点和 "RRD" 概念类似。

Capped collections是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能 和标准的collection不同,你必须要显式的创建一个capped collection 指定一个collection的大小,单位是字节。collection的数据存储空间值提前分配的。

 

要注意的是指定的存储大小包含了数据库的头信息。

 

db.createCollection("mycoll", {capped:true, size:100000})

 

·        capped collection中,你能添加新的对象。

·        能进行更新,然而,对象不会增加存储空间。如果增加,更新就会失败

·        数据库不允许进行删除。使用drop()方法删除collection所有的行。

·        注意: 删除之后,你必须显式的重新创建这个collection

·        32bit机器中,capped collection最大存储为1e9( 1X109)个字节。


4.3.4元数据

数据库的信息是存储在集合中。它们使用了系统的命名空间:

 

dbname.system.*

MongoDB数据库中名字空间 <dbname>.system.* 是包含多种系统信息的特殊集合(Collection),如下:

 

集合命名空间

描述

dbname.system.namespaces

列出所有名字空间。

dbname.system.indexes

列出所有索引。

dbname.system.profile

包含数据库概要(profile)信息。

dbname.system.users

列出所有可访问数据库的用户。

dbname.local.sources

包含复制对端(slave)的服务器信息和状态。

 

对于修改系统集合中的对象有如下限制。

{{system.indexes}}插入数据,可以创建索引。但除此之外该表信息是不可变的(特殊的drop index命令将自动更新相关信息)

{{system.users}}是可修改的。 {{system.profile}}是可删除的。


4.3.5 MongoDB 数据类型

下表为MongoDB中常用的几种数据类型。

 

数据类型

描述

String

字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。

Integer

整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。

Boolean

布尔值。用于存储布尔值(真/假)。

Double

双精度浮点值。用于存储浮点值。

Min/Max keys

将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。

Arrays

用于将数组或列表或多个值存储为一个键。

Timestamp

时间戳。记录文档修改或添加的具体时间。

Object

用于内嵌文档。

Null

用于创建空值。

Symbol

符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。

Date

日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:

创建 Date 对象,传入年月日信息。

Object ID

对象 ID。用于创建文档的 ID

Binary Data

二进制数据。用于存储二进制数据。

Code

代码类型。用于在文档中存储 JavaScript 代码。

Regular expression

正则表达式类型。用于存储正则表达式。

 

4.4 MongoDB连接

在本教程我们将讨论 MongoDB 的不同连接方式。


4.4.1 启动 MongoDB服务

在前面的教程中,我们已经讨论了如何启动MongoDB服务,你只需要在MongoDB安装目录的bin目录下执行'mongod'即可。

执行启动操作后,mongodb在输出一些必要信息后不会输出任何信息,之后就等待连接的建立,当连接被建立后,就会开始打印日志信息。

你可以使用 MongoDB shell 来连接 MongoDB 服务器。你也可以使用 PHP 来连接 MongoDB。本教程我们会使用 MongoDB shell 来连接 Mongodb 服务,之后的章节我们将会介绍如何通过php 来连接MongoDB服务。

 


4.4.2通过shell连接MongoDB服务

你可以通过执行以下命令来连接MongoDB的服务。

注意:localhost为主机名,这个选项是必须的:

 

mongodb://localhost

当你执行以上命令时,你可以看到以下输出结果:

 

$ ./mongo
MongoDB shell version: 3.0.6
connecting to: test
> mongodb://localhostmongodb://localhost
... 

这时候你返回查看运行 ./mongod 命令的窗口,可以看到是从哪里连接到MongoDB的服务器,您可以看到如下信息:

 

 
……省略信息……
2015-09-25T17:22:27.336+0800 I CONTROL  [initandlisten] allocator: tcmalloc
2015-09-25T17:22:27.336+0800 I CONTROL  [initandlisten] options: { storage: { dbPath: "/data/db" } }
2015-09-25T17:22:27.350+0800 I NETWORK  [initandlisten] waiting for connections on port 27017
2015-09-25T17:22:36.012+0800 I NETWORK  [initandlisten] connection accepted from 127.0.0.1:373
 
10 #1 (1 connection now open)  # 该行表明一个来自本机的连接
 
……省略信息……

 


4.4.3 MongoDB连接命令格式

使用用户名和密码连接到MongoDB服务器,你必须使用 'username:password@hostname/dbname' 格式,'username'为用户名,'password' 为密码。

使用用户名和密码连接登陆到默认数据库:

 

$ ./mongo
MongoDB shell version: 3.0.6
connecting to: test
mongodb://admin:123456@localhost/

以上命令中,用户 admin 使用密码 123456 连接到本地的 MongoDB 服务上。输出结果如下所示:<p>

 

> mongodb://admin:123456@localhost/
... 

使用用户名和密码连接登陆到指定数据库:

连接到指定数据库的格式如下:

 

mongodb://admin:123456@localhost/test

 


4.4.4 更多连接实例

连接本地数据库服务器,端口是默认的。

mongodb://localhost

使用用户名fred,密码foobar登录localhostadmin数据库。

mongodb://fred:foobar@localhost

使用用户名fred,密码foobar登录localhostbaz数据库。

mongodb://fred:foobar@localhost/baz

连接 replica pair, 服务器1example1.com服务器2example2

mongodb://example1.com:27017,example2.com:27017

连接 replica set 三台服务器 (端口 27017, 27018, 27019):

mongodb://localhost,localhost:27018,localhost:27019

连接 replica set 三台服务器, 写入操作应用在主服务器 并且分布查询到从服务器。

mongodb://host1,host2,host3/?slaveOk=true

直接连接第一个服务器,无论是replica set一部分或者主服务器或者从服务器。

mongodb://host1,host2,host3/?connect=direct;slaveOk=true

当你的连接服务器有优先级,还需要列出所有服务器,你可以使用上述连接方式。

安全模式连接到localhost:

mongodb://localhost/?safe=true

以安全模式连接到replica set,并且等待至少两个复制服务器成功写入,超时时间设置为2秒。

mongodb://host1,host2,host3/?safe=true;w=2;wtimeoutMS=2000

 


4.4.5 参数选项说明

标准格式:

 

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]

标准的连接格式包含了多个选项(options),如下所示:

 

选项

描述

replicaSet=name

验证replica set的名称。 Impliesconnect=replicaSet.

slaveOk=true|false

true:connect=direct模式下,驱动会连接第一台机器,即使这台服务器不是主。在

connect=replicaSet模式下,驱动会发送所有的写请求到主并且把读取操作分布在其他从服务器。

false: connect=direct模式下,驱动会自动找寻主服务器. connect=replicaSet 模式下,

驱动仅仅连接主服务器,并且所有的读写命令都连接到主服务器。

safe=true|false

true: 在执行更新操作之后,驱动都会发送getLastError命令来确保更新成功。

(还要参考 wtimeoutMS).

false: 在每次更新之后,驱动不会发送getLastError来确保更新成功。

w=n

驱动添加 { w : n } getLastError命令. 应用于safe=true

wtimeoutMS=ms

驱动添加 { wtimeout : ms } getlasterror 命令. 应用于 safe=true.

fsync=true|false

true: 驱动添加 { fsync : true } getlasterror 命令.应用于 safe=true.

false: 驱动不会添加到getLastError命令中。

journal=true|false

 

如果设置为 true, 同步到 journal (在提交到数据库前写入到实体中). 应用于 safe=true

connectTimeoutMS=ms

可以打开连接的时间。

socketTimeoutMS=ms

发送和接受sockets的时间。

 

4.5 MongoDB创建数据库

    4.5.1 语法

MongoDB 创建数据库的语法格式如下:

 

use DATABASE_NAME

如果数据库不存在,则创建数据库,否则切换到指定数据库。

 

4.5.2实例

以下实例我们创建了数据库 runoob:

 

> use runoob
switched to db runoob
> db
runoob
> 

如果你想查看所有数据库,可以使用 show dbs 命令:

 

> show dbsshow dbs
local  0.078GB
test   0.078GB
> 

可以看到,我们刚创建的数据库 runoob 并不在数据库的列表中, 要显示它,我们需要向 runoob 数据库插入一些数据。

 

> db.runoob.insert({"name":"菜鸟教程"})
WriteResult({ "nInserted" : 1 })
> show dbs
local   0.078GB
runoob  0.078GB
test    0.078GB
> 

MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中。

 

4.6 MongoDB删除数据库

4.6.1 语法

MongoDB 删除数据库的语法格式如下:

 

db.dropDatabase()

删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名。

 

4.6.2实例

以下实例我们删除了数据库 runoob

首先,查看所有数据库:

 

> show dbs
local   0.078GB
runoob  0.078GB
test    0.078GB

接下来我们切换到数据库 runoob

 

> use runoob
switched to db runoob
> 

执行删除命令:

 

> db.dropDatabase()
{ "dropped" : "runoob", "ok" : 1 }

最后,我们再通过 show dbs 命令数据库是否删除成功:

 

> show dbs
local  0.078GB
test   0.078GB
> 

 

 

4.7 MongoDB插入文档

本章节中我们将向大家介绍如何将数据插入到MongoDB的集合中。

文档的数据结构和JSON基本一样。

所有存储在集合中的数据都是BSON格式。

BSON是一种类json的一种二进制形式的存储格式,简称Binary JSON

 

4.7.1 插入文档

MongoDB 使用 insert() save() 方法向集合中插入文档,语法如下:

 

db.COLLECTION_NAME.insert(document)

 

4.7.2 实例

以下文档可以存储在 MongoDB runoob 数据库 col集合中:

 

>db.col.insert({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
})

以上实例中 col 是我们的集合名,前一章节我们已经创建过了,如果该集合不在该数据库中, MongoDB 会自动创建该集合比插入文档。

查看已插入文档:

 

> db.col.find()
{ "_id" : ObjectId("56064886ade2f21f36b03134"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }
> 

我们也可以将数据定义为一个变量,如下所示:

 

> document=({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
});

执行后显示结果如下:

 

{
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}

执行插入操作:

 

> db.col.insert(document)
WriteResult({ "nInserted" : 1 })
> 

插入文档你也可以使用 db.col.save(document) 命令。如果不指定 _id 字段 save() 方法类似于 insert() 方法。如果指定 _id 字段,则会更新该 _id 的数据。

 

 

 

 

4.8 MongoDB更新文档

MongoDB 使用 update()  save() 方法来更新集合中的文档。接下来让我们详细来看下两个函数的应用及其区别。


4.8.1 update() 方法

update() 方法用于更新已存在的文档。语法格式如下:

db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)

参数说明:

·        query : update的查询条件,类似sql update查询内where后面的。

·        update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的

·        upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。

·        multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。

·        writeConcern :可选,抛出异常的级别。

 

4.8.2 实例

我们在集合 col 中插入如下数据:

>db.col.insert({
    title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
})

接着我们通过 update() 方法来更新标题(title):

>db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })   # 输出信息
> db.col.find().pretty()
{
        "_id" : ObjectId("56064f89ade2f21f36b03136"),
        "title" : "MongoDB",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}
> 

可以看到标题(title)由原来的 "MongoDB 教程" 更新为了 "MongoDB"

以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true

>db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})

4.8.3 save() 方法

save() 方法通过传入的文档来替换已有文档。语法格式如下:

db.collection.save(
   <document>,
   {
     writeConcern: <document>
   }
)

参数说明:

·        document : 文档数据。

·        writeConcern :可选,抛出异常的级别。

 

4.8.4 实例

以下实例中我们替换了 _id 56064f89ade2f21f36b03136 的文档数据:

>db.col.save({
        "_id" : ObjectId("56064f89ade2f21f36b03136"),
    "title" : "MongoDB",
    "description" : "MongoDB 是一个 Nosql 数据库",
    "by" : "Runoob",
    "url" : "http://www.runoob.com",
    "tags" : [
            "mongodb",
            "NoSQL"
    ],
    "likes" : 110
})

替换成功后,我们可以通过 find() 命令来查看替换后的数据

>db.col.find().pretty()
{
        "_id" : ObjectId("56064f89ade2f21f36b03136"),
        "title" : "MongoDB",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "Runoob",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "NoSQL"
        ],
        "likes" : 110
}
> 

4.8.5更多实例

只更新第一条记录:

db.col.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } );

全部更新:

db.col.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );

只添加第一条:

db.col.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );

全部添加加进去:

db.col.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );

全部更新:

db.col.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );

只更新第一条记录:

db.col.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );

 

4.9 MongoDB删除文档

在前面的几个章节中我们已经学习了MongoDB中如何为集合添加数据和更新数据。在本章节中我们将继续学习MongoDB集合的删除。

MongoDB remove()函数是用来移除集合中的数据。

MongoDB数据更新可以使用update()函数。在执行remove()函数前先执行find()命令来判断执行的条件是否正确,这是一个比较好的习惯。

 

4.9.1语法

remove() 方法的基本语法格式如下所示:

 

db.collection.remove(
   <query>,
   <justOne>
)

如果你的 MongoDB 2.6 版本以后的,语法格式如下:

 

db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>
   }
)

参数说明:

·        query :(可选)删除的文档的条件。

·        justOne : (可选)如果设为 true 1,则只删除一个文档。

·        writeConcern :(可选)抛出异常的级别。

 

4.9.2 实例

以下文档我们执行两次插入操作:

 

>db.col.insert({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
})

使用 find() 函数查询数据:

 

> db.col.find()
{ "_id" : ObjectId("56066169ade2f21f36b03137"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }
{ "_id" : ObjectId("5606616dade2f21f36b03138"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100 }

接下来我们移除 title 'MongoDB 教程' 的文档:

 

>db.col.remove({'title':'MongoDB 教程'})
WriteResult({ "nRemoved" : 2 })           # 删除了两条数据
>db.col.find()
……                                        # 没有数据

如果你只想删除第一条找到的记录可以设置 justOne 1,如下所示:

>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)

如果你想删除所有数据,可以使用以下方式(类似常规 SQL truncate 命令):

 

>db.col.remove({})
>db.col.find()
> 

 

4.10 MongoDB查找文档

4.10.1 语法

MongoDB 查询数据的语法格式如下:

 

>db.COLLECTION_NAME.find()

find() 方法以非结构化的方式来显示所有文档。

如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:

 

>db.col.find().pretty()

pretty() 方法以格式化的方式来显示所有文档。

 

以下实例我们删除了数据库 runoob

 

> db.col.find().pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}

除了 find() 方法之外,还有一个 findOne() 方法,它只返回一个文档。


4.10.2 MongoDB RDBMS Where 语句比较

如果你熟悉常规的 SQL 数据,通过下表可以更好的理解 MongoDB 的条件语句查询:

 

操作

格式

范例

RDBMS中的类似语句

等于

{<key>:<value>}

db.col.find({"by":"菜鸟教程"}).pretty()

where by = '菜鸟教程'

小于

{<key>:{$lt:<value>}}

db.col.find({"likes":{$lt:50}}).pretty()

where likes < 50

小于或等于

{<key>:{$lte:<value>}}

db.col.find({"likes":{$lte:50}}).pretty()

where likes <= 50

大于

{<key>:{$gt:<value>}}

db.col.find({"likes":{$gt:50}}).pretty()

where likes > 50

大于或等于

{<key>:{$gte:<value>}}

db.col.find({"likes":{$gte:50}}).pretty()

where likes >= 50

不等于

{<key>:{$ne:<value>}}

db.col.find({"likes":{$ne:50}}).pretty()

where likes != 50


4.10.3 MongoDB AND 条件

MongoDB find() 方法可以传入多个键(key),每个键(key)以逗号隔开,及常规 SQL AND 条件。

语法格式如下:

 

>db.col.find({key1:value1, key2:value2}).pretty()

以下实例通过 by  title 键来查询 菜鸟教程  MongoDB 教程 的数据

 

> db.col.find({"by":"菜鸟教程", "title":"MongoDB 教程"}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}

以上实例中类似于 WHERE 语句:WHERE by='菜鸟教程' AND title='MongoDB 教程'


4.10.4 MongoDB OR 条件

MongoDB OR 条件语句使用了关键字 $or,语法格式如下:

>db.col.find(
   {
      $or: [
             {key1: value1}, {key2:value2}
      ]
   }
).pretty()

以下实例中,我们演示了查询键 by 值为 菜鸟教程 或键 title 值为 MongoDB 教程 的文档。

 

>db.col.find({$or:[{"by":"菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}
> 

4.10.5 AND OR 联合使用

以下实例演示了 AND OR 联合使用,类似常规 SQL 语句为: 'where url='http://www.runoob.com' AND (by = '菜鸟教程' OR title = 'MongoDB 教程')'

 

>db.col.find({"likes": {$gt:50}, $or: [{"by": "菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
{
        "_id" : ObjectId("56063f17ade2f21f36b03133"),
        "title" : "MongoDB 教程",
        "description" : "MongoDB 是一个 Nosql 数据库",
        "by" : "菜鸟教程",
        "url" : "http://www.runoob.com",
        "tags" : [
                "mongodb",
                "database",
                "NoSQL"
        ],
        "likes" : 100
}

 

4.11 MongoDB条件操作符

4.11.1 描述

条件操作符用于比较两个表达式并从mongoDB集合中获取数据。

在本章节中,我们将讨论如何在MongoDB中使用条件操作符。

MongoDB中条件操作符有:

 

·        (>) 大于 - $gt

·        (<) 小于 - $lt

·        (>=) 大于等于 - $gte

·        (<= ) 小于等于 - $lte

我们使用的数据库名称为"runoob" 我们的集合名称为"col",以下为我们插入的数据。

为了方便测试,我们可以先使用以下命令清空集合 "col" 的数据:

 

 db.col.remove({})db.col.remove({})
 

插入以下数据

 

>db.col.insert({
    title: 'PHP 教程', 
    description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['php'],
    likes: 200
})



>db.col.insert({title: 'Java 教程', 
    description: 'Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['java'],
    likes: 150
})



>db.col.insert({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['mongodb'],
    likes: 100
})

使用find()命令查看数据:

 

> db.col.find()
{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "php" ], "likes" : 200 }
{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }
{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb" ], "likes" : 100 }



4.11.2 MongoDB (>) 大于操作符 - $gt

如果你想获取 "col" 集合中 "likes" 大于 100 的数据,你可以使用以下命令:

 

db.col.find({"likes" : {$gt : 100}})

类似于SQL语句:

 

Select * from col where likes > 22;

输出结果:

 

> db.col.find({"likes" : {$gt : 100}})
{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "php" ], "likes" : 200 }
{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }
> 



4.11.3 MongoDB>=)大于等于操作符 - $gte

如果你想获取"col"集合中 "likes" 大于等于 100 的数据,你可以使用以下命令:

 

db.col.find({likes : {$gte : 100}})

类似于SQL语句:

 

Select * from col where likes >=100;

输出结果:

 

> db.col.find({likes : {$gte : 100}})
{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "php" ], "likes" : 200 }
{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }
{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb" ], "likes" : 100 }
> 



4.11.4 MongoDB (<) 小于操作符 - $lt

如果你想获取"col"集合中 "likes" 小于 150 的数据,你可以使用以下命令:

 

db.col.find({likes : {$lt : 150}})

类似于SQL语句:

 

Select * from col where likes < 150;

输出结果:

 

> db.col.find({likes : {$lt : 150}})
{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb" ], "likes" : 100 }



4.11.5 MongoDB (<=) 小于操作符 - $lte

如果你想获取"col"集合中 "likes" 小于等于 150 的数据,你可以使用以下命令:

 

db.col.find({likes : {$lte : 150}})

类似于SQL语句:

 

Select * from col where likes <= 150;

输出结果:

 

> db.col.find({likes : {$lte : 150}})
{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }
{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb" ], "likes" : 100 }



4.11.6 MongoDB 使用 (<) (>) 查询 - $lt $gt

如果你想获取"col"集合中 "likes" 大于100,小于 200 的数据,你可以使用以下命令:

 

db.col.find({likes : {$lt :200, $gt : 100}})

类似于SQL语句:

 

Select * from col where likes>100 AND  likes<200;

输出结果:

 

> db.col.find({likes : {$lt :200, $gt : 100}})
{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }
> 

 

4.12 MongoDB  $type 操作符

4.12.1 描述

在本章节中,我们将继续讨论MongoDB中条件操作符 $type

$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。

MongoDB 中可以使用的类型如下表所示:

 

类型

数字

备注

Double

1

 

String

2

 

Object

3

 

Array

4

 

Binary data

5

 

Undefined

6

已废弃。

Object id

7

 

Boolean

8

 

Date

9

 

Null

10

 

Regular Expression

11

 

JavaScript

13

 

Symbol

14

 

JavaScript (with scope)

15

 

32-bit integer

16

 

Timestamp

17

 

64-bit integer

18

 

Min key

255

Query with -1.

Max key

127

 

我们使用的数据库名称为"runoob" 我们的集合名称为"col",以下为我们插入的数据。

简单的集合"col"

 

>db.col.insert({
    title: 'PHP 教程', 
    description: 'PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['php'],
    likes: 200
})



>db.col.insert({title: 'Java 教程', 
    description: 'Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['java'],
    likes: 150
})



>db.col.insert({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: '菜鸟教程',
    url: 'http://www.runoob.com',
    tags: ['mongodb'],
    likes: 100
})

使用find()命令查看数据:

 

> db.col.find()
{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "php" ], "likes" : 200 }
{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }
{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb" ], "likes" : 100 }



4.12.2 MongoDB 操作符 - $type 实例

如果想获取 "col" 集合中 title String 的数据,你可以使用以下命令:

 

db.col.find({"title" : {$type : 2}})

输出结果为:

 

{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "php" ], "likes" : 200 }
{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }
{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb" ], "likes" : 100 }

 

 

 

 

 

4. 13  MongoDB  LimitSkip方法

4.13.1 MongoDB Limit() 方法

如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDBLimit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。

limit()方法基本语法如下所示:

>db.COLLECTION_NAME.find().limit(NUMBER)

集合 col 中的数据如下:

{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "php" ], "likes" : 200 }

{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }

{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb" ], "likes" : 100 }

 

以上实例为显示查询文档中的两条记录:

> db.col.find({},{"title":1,_id:0}).limit(2)

{ "title" : "PHP 教程" }

{ "title" : "Java 教程" }

> 

注:如果你们没有指定limit()方法中的参数则显示集合中的所有数据。


4.13.2 MongoDB Skip() 方法

我们除了可以使用limit()方法来读取指定数量的数据外,还可以使用skip()方法来跳过指定数量的数据,skip方法同样接受一个数字参数作为跳过的记录条数。

skip() 方法脚本语法格式如下:

>db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)

 

以上实例只会显示第二条文档数据

>db.col.find({},{"title":1,_id:0}).limit(1).skip(1)

{ "title" : "Java 教程" }

> 

:skip()方法默认参数为 0

 

 

4.14 MongoDB排序

4.14.1 MongoDB sort()方法

MongoDB中使用使用sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用 1 -1 来指定排序的方式,其中 1 为升

序排列,而-1是用于降序排列。

sort()方法基本语法如下所示:

>db.COLLECTION_NAME.find().sort({KEY:1})

col 集合中的数据如下:

{ "_id" : ObjectId("56066542ade2f21f36b0313a"), "title" : "PHP 教程", "description" : "PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "php" ], "likes" : 200 }

{ "_id" : ObjectId("56066549ade2f21f36b0313b"), "title" : "Java 教程", "description" : "Java 是由Sun Microsystems公司于19955月推出的高级程序设计语言。", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "java" ], "likes" : 150 }

{ "_id" : ObjectId("5606654fade2f21f36b0313c"), "title" : "MongoDB 教程", "description" : "MongoDB 是一个 Nosql 数据库", "by" : "菜鸟教程", "url" : "http://www.runoob.com", "tags" : [ "mongodb" ], "likes" : 100 }

 

以下实例演示了 col 集合中的数据按字段 likes 的降序排列:

>db.col.find({},{"title":1,_id:0}).sort({"likes":-1})

{ "title" : "PHP 教程" }

{ "title" : "Java 教程" }

{ "title" : "MongoDB 教程" }

> 

注: 如果没有指定sort()方法的排序方式,默认按照文档的升序排列。

 

4.15 MongoDB索引

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。

这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构


4.15.1 ensureIndex() 方法

MongoDB使用 ensureIndex() 方法来创建索引。

ensureIndex()方法基本语法格式如下所示:

>db.COLLECTION_NAME.ensureIndex({KEY:1})

语法中 Key 值为你要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为-1即可。

>db.col.ensureIndex({"title":1})
> 

ensureIndex() 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。

>db.col.ensureIndex({"title":1,"description":-1})
> 

ensureIndex() 接收可选参数,可选参数列表如下:

 

Parameter

Type

Description

background

Boolean

建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false

unique

Boolean

建立的索引是否唯一。指定为true创建唯一索引。默认值为false.

name

string

索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。

dropDups

Boolean

在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.

sparse

Boolean

对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.

expireAfterSeconds

integer

指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。

v

index version

索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。

weights

document

索引权重值,数值在 1 99,999 之间,表示该索引相对于其他索引字段的得分权重。

default_language

string

对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语

language_override

string

对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

在后台创建索引:

db.values.ensureIndex({open: 1, close: 1}, {background: true})

通过在创建索引时加background:true 的选项,让创建工作在后台执行

 

 

4.16 MongoDB聚合

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。

这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构


4.16.1 ensureIndex() 方法

MongoDB使用 ensureIndex() 方法来创建索引。

ensureIndex()方法基本语法格式如下所示:

>db.COLLECTION_NAME.ensureIndex({KEY:1})

语法中 Key 值为你要创建的索引字段,1为指定按升序创建索引,如果你想按降序来创建索引指定为-1即可。

 

>db.col.ensureIndex({"title":1})
> 

ensureIndex() 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。

 

>db.col.ensureIndex({"title":1,"description":-1})
> 

ensureIndex() 接收可选参数,可选参数列表如下:

 

Parameter

Type

Description

background

Boolean

建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false

unique

Boolean

建立的索引是否唯一。指定为true创建唯一索引。默认值为false.

name

string

索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。

dropDups

Boolean

在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.

sparse

Boolean

对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.

expireAfterSeconds

integer

指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。

v

index version

索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。

weights

document

索引权重值,数值在 1 99,999 之间,表示该索引相对于其他索引字段的得分权重。

default_language

string

对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语

language_override

string

对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

在后台创建索引:

 

db.values.ensureIndex({open: 1, close: 1}, {background: true})

通过在创建索引时加background:true 的选项,让创建工作在后台执行

 

 

4.17 MongoDB复制

MongoDB复制是将数据同步在多个服务器的过程。

复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。

复制还允许您从硬件故障和服务中断中恢复数据。

 

4.17.1 什么是复制?

保障数据的安全性

数据高可用性 (24*7)

灾难恢复

无需停机维护(如备份,重建索引,压缩)

分布式读取数据

4.17.2 MongoDB复制原理

mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。

mongodb各个节点常见的搭配方式为:一主一从、一主多从。

主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。

MongoDB复制结构图如下所示:

MongoDB复制结构图

以上结构图总,客户端总主节点读取数据,在客户端写入数据到主节点是, 主节点与从节点进行数据交互保障数据的一致性。

4.17.3 副本集特征:

N 个节点的集群

任何节点可作为主节点

所有写入操作都在主节点上

自动故障转移

自动恢复

4.17.4 MongoDB副本集设置

在本教程中我们使用同一个MongoDB来做MongoDB主从的实验, 操作步骤如下:

1、关闭正在运行的MongoDB服务器。

现在我们通过指定 --replSet 选项来启动mongoDB--replSet 基本语法格式如下:

mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0

以上实例会启动一个名为rs0MongoDB实例,其端口号为27017

启动后打开命令提示框并连接上mongoDB服务。

Mongo客户端使用命令rs.initiate()来启动一个新的副本集。

我们可以使用rs.conf()来查看副本集的配置

查看副本集姿态使用 rs.status() 命令

4.17.5副本集添加成员

添加副本集的成员,我们需要使用多条服务器来启动mongo服务。进入Mongo客户端,并使用rs.add()方法来添加副本集的成员。

rs.add() 命令基本语法格式如下:

>rs.add(HOST_NAME:PORT)

假设你已经启动了一个名为mongod1.net,端口号为27017Mongo服务。 在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示:

>rs.add("mongod1.net:27017")
> 

MongoDB中你只能通过主节点将Mongo服务添加到副本集中, 判断当前运行的Mongo服务是否为主节点可以使用命令db.isMaster()

MongoDB的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点,不会出现宕机的情况。

 

4.18 MongoDB分片

4.18.1 分片

Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。

MongoDB存储海量的数据时,一台机器可能不足以存储数据也足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。


4.18.2 为什么使用分片

复制所有的写入操作到主节点

延迟的敏感数据会在主节点查询

单个副本集限制在12个节点

当请求量巨大时会出现内存不足。

本地磁盘不足

垂直扩展价格昂贵


4.18.3 MongoDB分片

下图展示了在MongoDB中使用分片集群结构分布:

http://www.runoob.com/wp-content/uploads/2013/12/sharding.png

上图中主要有如下所述三个主要组件:

用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个relica set承担,防止主机单点故障

mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。

前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。


4.18.4分片实例

分片结构端口分布如下:

Shard Server 127020
Shard Server 227021
Shard Server 327022
Shard Server 427023
Config Server 27100
Route Process40000
 
步骤一:启动Shard Server
 
[root@100 /]# mkdir -p /www/mongoDB/shard/s0
[root@100 /]# mkdir -p /www/mongoDB/shard/s1
[root@100 /]# mkdir -p /www/mongoDB/shard/s2
[root@100 /]# mkdir -p /www/mongoDB/shard/s3
[root@100 /]# mkdir -p /www/mongoDB/shard/log
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27020 --dbpath=/www/mongoDB/shard/s0 --logpath=/www/mongoDB/shard/log/s0.log --logappend --fork
....
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27023 --dbpath=/www/mongoDB/shard/s3 --logpath=/www/mongoDB/shard/log/s3.log --logappend –fork
 
步骤二: 启动Config Server
 
[root@100 /]# mkdir -p /www/mongoDB/shard/config
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27100 --dbpath=/www/mongoDB/shard/config --logpath=/www/mongoDB/shard/log/config.log --logappend –fork
 

注意:这里我们完全可以像启动普通mongodb服务一样启动,不需要添加—shardsvrconfigsvr参数。因为这两个参数的作用就是改变启动端口的,所以我们自行指定了端口就可以。

步骤三: 启动Route Process

/usr/local/mongoDB/bin/mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500

mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,单位是MB,默认大小为200MB.

步骤四: 配置Sharding

接下来,我们使用MongoDB Shell登录到mongos,添加Shard节点
 
[root@100 shard]# /usr/local/mongoDB/bin/mongo admin --port 40000
 
MongoDB shell version: 2.0.7
connecting to: 127.0.0.1:40000/admin
 
mongos> db.runCommand({ addshard:"localhost:27020" })
{ "shardAdded" : "shard0000", "ok" : 1 }
 
......
 
mongos> db.runCommand({ addshard:"localhost:27029" })
{ "shardAdded" : "shard0009", "ok" : 1 }
 
 
mongos> db.runCommand({ enablesharding:"test" }) #设置分片存储的数据库
{ "ok" : 1 }
 
 
mongos> db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}})
{ "collectionsharded" : "test.log", "ok" : 1 }
 

步骤五: 程序代码内无需太大更改,直接按照连接普通的mongo数据库那样,将数据库连接接入接口40000

 

 

 

4.19 MongoDB备份(mongodump)与恢复(mongorerstore)

4.19.1 MongoDB数据备份

Mongodb中我们使用mongodump命令来备份MongoDB数据。该命令可以导出所有数据到指定目录中。

mongodump命令可以通过参数指定导出的数据量级转存的服务器。

mongodump命令脚本语法如下:

>mongodump -h dbhost -d dbname -o dbdirectory

·        -h

MongDB所在服务器地址,例如:127.0.0.1,当然也可以指定端口号:127.0.0.1:27017

·        -d

需要备份的数据库实例,例如:test

·        -o

备份的数据存放位置,例如:c:\data\dump,当然该目录需要提前建立,在备份完成后,系统自动在dump目录下建立一个test目录,这个目录里面存放该数据库实例的备份数据。

 

在本地使用 27017 启动你的mongod服务。打开命令提示符窗口,进入MongoDB安装目录的bin目录输入命令mongodump:

        >mongodump

执行以上命令后,客户端会连接到ip 127.0.0.1 端口号为 27017 MongoDB服务上,并备份所有数据到 bin/dump/ 目录中。命令输出结果如下:

MongoDB数据备份

mongodump 命令可选参数列表如下所示:

 


4.19.2 MongoDB数据恢复

mongodb使用 mongorerstore 命令来恢复备份的数据。

mongorestore命令脚本语法如下:

>mongorestore -h dbhost -d dbname --directoryperdb dbdirectory

·        -h

MongoDB所在服务器地址

·        -d

需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2

·        --directoryperdb

备份数据所在位置,例如:c:\data\dump\test,这里为什么要多加一个test,而不是备份时候的dump,读者自己查看提示吧!

·        --drop

恢复的时候,先删除当前数据,然后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用哦!

接下来我们执行以下命令:

        >mongorestore

执行以上命令输出结果如下:

MongoDB数据恢复

 

4.20 MongoDB监控

在你已经安装部署并允许MongoDB服务后,你必须要了解MongoDB的运行情况,并查看MongoDB的性能。这样在大流量得情况下可以

很好的应对并保证MongoDB正常运作。

MongoDB中提供了mongostat mongotop 两个命令来监控MongoDB的运行情况。


4.20.1 mongostat 命令

mongostatmongodb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出。如果你发现

数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。

启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongostat命令,如下所示:

D:\set up\mongodb\bin>mongostat

以上命令输出结果如下:

http://www.runoob.com/wp-content/uploads/2013/12/mongostat.png

4.20.2 mongotop 命令

mongotop也是mongodb下的一个内置工具,mongotop提供了一个方法,用来跟踪一个MongoDB的实例,查看哪些大量的时间花费在读取和写入数据。 mongotop提供每个集合的水平的统计数据。默认情况下,mongotop返回值的每一秒。

启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongotop命令,如下所示:

D:\set up\mongodb\bin>mongotop

以上命令执行输出结果如下:

http://www.runoob.com/wp-content/uploads/2013/12/mongotop.png

带参数实例

 E:\mongodb-win32-x86_64-2.2.1\bin>mongotop 10

http://www.runoob.com/wp-content/uploads/2013/12/29122412-e32a9f09e46e496a8833433fdb421311.gif

后面的10<sleeptime>参数 ,可以不使用,等待的时间长度,以秒为单位,mongotop等待调用之间。通过的默认mongotop返回数据的每一秒。

 E:\mongodb-win32-x86_64-2.2.1\bin>mongotop --locks

报告每个数据库的锁的使用中,使用mongotop - 锁,这将产生以下输出:

http://www.runoob.com/wp-content/uploads/2013/12/29122706-bfdd58e62c404b948f8039c489f8be81.gif

输出结果字段说明:

ns

包含数据库命名空间,后者结合了数据库名称和集合。

db

包含数据库的名称。名为 . 的数据库针对全局锁定,而非特定数据库。

total

mongod花费的时间工作在这个命名空间提供总额。

read

提供了大量的时间,这mongod花费在执行读操作,在此命名空间。

write

提供这个命名空间进行写操作,这mongod花了大量的时间。

 

5JAVA操作MongoDB

环境配置

Java程序中如果要使用MongoDB,你需要确保已经安装了Java环境及MongoDB JDBC 驱动。

你可以参考本站的Java教程来安装Java程序。现在让我们来检测你是否安装了 MongoDB JDBC 驱动。

A. 首先你必须下载mongo jar包,下载地址:https://github.com/mongodb/mongo-java-driver/downloads, 请确保下载最新版本。

B.  你需要将mongo.jar包含在你的 classpath 中。

首先介绍一下比较常用的几个类

Mongo:连接服务器,执行一些数据库操作的选项,如新建立一个数据库等

DB:对应一个数据库,可以用来建立集合等操作

DBCollection:对应一个集合(类似表),可能是我们用得最多的,可以添加删除记录等

DBObjec:接口和BasicDBObject对象:表示一个具体的记录,BasicDBObject实现了DBObject,因为是key-value的数据结构,所以用起来其实和HashMap是基本一致的

DBCursor:用来遍历取得的数据,实现了IterableIterator

连接数据库

 

连接数据库,你需要指定数据库名称,如果指定的数据库不存在,mongo会自动创建数据库。

 

连接数据库的Java代码如下:

 

import com.mongodb.MongoClient;

import com.mongodb.MongoException;

import com.mongodb.WriteConcern;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.BasicDBObject;

import com.mongodb.DBObject;

import com.mongodb.DBCursor;

import com.mongodb.ServerAddress;

import java.util.Arrays;

 

public class MongoDBJDBC{

   public static void main( String args[] ){

      try{  

                       // 连接到 mongodb 服务

         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );

         // 连接到数据库

         DB db = mongoClient.getDB( "test" );

                       System.out.println("Connect to database successfully");

         boolean auth = db.authenticate(myUserName, myPassword);

                       System.out.println("Authentication: "+auth);

      }catch(Exception e){

        System.err.println( e.getClass().getName() + ": " + e.getMessage() );

     }

   }

}

 

现在,让我们来编译运行程序并创建数据库test

 

你可以更加你的实际环境改变MongoDB JDBC驱动的路径。

 

本实例将MongoDB JDBC启动包 mongo-2.10.1.jar 放在本地目录下:

 

$javac MongoDBJDBC.java

$java -classpath ".:mongo-2.10.1.jar" MongoDBJDBC

Connect to database successfully

Authentication: true

 

如果你使用的是Window系统,你可以按以下命令来编译执行程序:

 

$javac MongoDBJDBC.java

$java -classpath ".;mongo-2.10.1.jar" MongoDBJDBC

Connect to database successfully

Authentication: true

 

如果用户名及密码正确,则Authentication 的值为true

创建集合

 

我们可以使用com.mongodb.DB类中的createCollection()来创建集合

 

代码片段如下:

 

import com.mongodb.MongoClient;

import com.mongodb.MongoException;

import com.mongodb.WriteConcern;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.BasicDBObject;

import com.mongodb.DBObject;

import com.mongodb.DBCursor;

import com.mongodb.ServerAddress;

import java.util.Arrays;

 

public class MongoDBJDBC{

   public static void main( String args[] ){

      try{  

                       // 连接到 mongodb 服务

         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );

         // 连接到数据库

         DB db = mongoClient.getDB( "test" );

                   System.out.println("Connect to database successfully");

         boolean auth = db.authenticate(myUserName, myPassword);

                   System.out.println("Authentication: "+auth);

         DBCollection coll = db.createCollection("mycol");

         System.out.println("Collection created successfully");

      }catch(Exception e){

                       System.err.println( e.getClass().getName() + ": " + e.getMessage() );

                    }

   }

}

 

编译运行以上程序,输出结果如下:

 

Connect to database successfully

Authentication: true

Collection created successfully

 

获取集合

 

我们可以使用com.mongodb.DBCollection类的 getCollection() 方法来获取一个集合

 

代码片段如下:

 

import com.mongodb.MongoClient;

import com.mongodb.MongoException;

import com.mongodb.WriteConcern;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.BasicDBObject;

import com.mongodb.DBObject;

import com.mongodb.DBCursor;

import com.mongodb.ServerAddress;

import java.util.Arrays;

 

public class MongoDBJDBC{

   public static void main( String args[] ){

      try{  

                  // 连接到 mongodb 服务

         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );

         // 连接到数据库

         DB db = mongoClient.getDB( "test" );

              System.out.println("Connect to database successfully");

         boolean auth = db.authenticate(myUserName, myPassword);

              System.out.println("Authentication: "+auth);

         DBCollection coll = db.createCollection("mycol");

         System.out.println("Collection created successfully");

         DBCollection coll = db.getCollection("mycol");

         System.out.println("Collection mycol selected successfully");

      }catch(Exception e){

                  System.err.println( e.getClass().getName() + ": " + e.getMessage() );

               }

   }

}

 

编译运行以上程序,输出结果如下:

 

Connect to database successfully

Authentication: true

Collection created successfully

Collection mycol selected successfully

 

插入文档

 

我们可以使用com.mongodb.DBCollection类的 insert() 方法来插入一个文档

 

代码片段如下:

 

import com.mongodb.MongoClient;

import com.mongodb.MongoException;

import com.mongodb.WriteConcern;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.BasicDBObject;

import com.mongodb.DBObject;

import com.mongodb.DBCursor;

import com.mongodb.ServerAddress;

import java.util.Arrays;

 

public class MongoDBJDBC{

   public static void main( String args[] ){

      try{  

                                      // 连接到 mongodb 服务

         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );

         // 连接到数据库

         DB db = mongoClient.getDB( "test" );

                   System.out.println("Connect to database successfully");

         boolean auth = db.authenticate(myUserName, myPassword);

                   System.out.println("Authentication: "+auth);        

         DBCollection coll = db.getCollection("mycol");

         System.out.println("Collection mycol selected successfully");

         BasicDBObject doc = new BasicDBObject("title", "MongoDB").

            append("description", "database").

            append("likes", 100).

            append("url", "http://www.w3cschool.cc/mongodb/").

            append("by", "w3cschool.cc");

         coll.insert(doc);

         System.out.println("Document inserted successfully");

      }catch(Exception e){

                       System.err.println( e.getClass().getName() + ": " + e.getMessage() );

                    }

   }

}

 

编译运行以上程序,输出结果如下:

 

Connect to database successfully

Authentication: true

Collection mycol selected successfully

Document inserted successfully

 

检索所有文档

 

我们可以使用com.mongodb.DBCollection类中的 find() 方法来获取集合中的所有文档。

 

此方法返回一个游标,所以你需要遍历这个游标。

 

代码片段如下:

 

import com.mongodb.MongoClient;

import com.mongodb.MongoException;

import com.mongodb.WriteConcern;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.BasicDBObject;

import com.mongodb.DBObject;

import com.mongodb.DBCursor;

import com.mongodb.ServerAddress;

import java.util.Arrays;

 

public class MongoDBJDBC{

   public static void main( String args[] ){

      try{  

                                     // 连接到 mongodb 服务

         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );

          // 连接到数据库

         DB db = mongoClient.getDB( "test" );

                   System.out.println("Connect to database successfully");

         boolean auth = db.authenticate(myUserName, myPassword);

                   System.out.println("Authentication: "+auth);        

         DBCollection coll = db.getCollection("mycol");

         System.out.println("Collection mycol selected successfully");

         DBCursor cursor = coll.find();

         int i=1;

         while (cursor.hasNext()) {

            System.out.println("Inserted Document: "+i);

            System.out.println(cursor.next());

            i++;

         }

      }catch(Exception e){

                       System.err.println( e.getClass().getName() + ": " + e.getMessage() );

                    }

   }

}

 

编译运行以上程序,输出结果如下:

 

Connect to database successfully

Authentication: true

Collection mycol selected successfully

Inserted Document: 1

{

   "_id" : ObjectId(7df78ad8902c),

   "title": "MongoDB",

   "description": "database",

   "likes": 100,

   "url": "http://www.w3cschool.cc/mongodb/",

   "by": "w3cschool.cc"

}

 

更新文档

 

你可以使用 com.mongodb.DBCollection 类中的 update() 方法来更新集合中的文档。

 

代码片段如下:

 

import com.mongodb.MongoClient;

import com.mongodb.MongoException;

import com.mongodb.WriteConcern;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.BasicDBObject;

import com.mongodb.DBObject;

import com.mongodb.DBCursor;

import com.mongodb.ServerAddress;

import java.util.Arrays;

 

public class MongoDBJDBC{

   public static void main( String args[] ){

      try{  

                   // 连接到Mongodb服务

         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );

         // 连接到你的数据库

         DB db = mongoClient.getDB( "test" );

                   System.out.println("Connect to database successfully");

         boolean auth = db.authenticate(myUserName, myPassword);

                   System.out.println("Authentication: "+auth);        

         DBCollection coll = db.getCollection("mycol");

         System.out.println("Collection mycol selected successfully");

         DBCursor cursor = coll.find();

         while (cursor.hasNext()) {

            DBObject updateDocument = cursor.next();

            updateDocument.put("likes","200")

            col1.update(updateDocument);

         }

         System.out.println("Document updated successfully");

         cursor = coll.find();

         int i=1;

         while (cursor.hasNext()) {

            System.out.println("Updated Document: "+i);

            System.out.println(cursor.next());

            i++;

         }

      }catch(Exception e){

                       System.err.println( e.getClass().getName() + ": " + e.getMessage() );

                    }

   }

}

 

编译运行以上程序,输出结果如下:

 

Connect to database successfully

Authentication: true

Collection mycol selected successfully

Document updated successfully

Updated Document: 1

{

   "_id" : ObjectId(7df78ad8902c),

   "title": "MongoDB",

   "description": "database",

   "likes": 200,

   "url": "http://www.w3cschool.cc/mongodb/",

   "by": "w3cschool.cc"

}

 

删除第一个文档

 

要删除集合中的第一个文档,首先你需要使用com.mongodb.DBCollection类中的 findOne()方法来获取第一个文档,然后使用remove 方法删除。

 

代码片段如下:

 

 import com.mongodb.MongoClient;

import com.mongodb.MongoException;

import com.mongodb.WriteConcern;

import com.mongodb.DB;

import com.mongodb.DBCollection;

import com.mongodb.BasicDBObject;

import com.mongodb.DBObject;

import com.mongodb.DBCursor;

import com.mongodb.ServerAddress;

import java.util.Arrays;

 

public class MongoDBJDBC{

   public static void main( String args[] ){

      try{  

                   // 连接到Mongodb服务

         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );

         // 连接到你的数据库

         DB db = mongoClient.getDB( "test" );

                   System.out.println("Connect to database successfully");

         boolean auth = db.authenticate(myUserName, myPassword);

                   System.out.println("Authentication: "+auth);        

         DBCollection coll = db.getCollection("mycol");

         System.out.println("Collection mycol selected successfully");

         DBObject myDoc = coll.findOne();

         col1.remove(myDoc);

         DBCursor cursor = coll.find();

         int i=1;

         while (cursor.hasNext()) {

            System.out.println("Inserted Document: "+i);

            System.out.println(cursor.next());

            i++;

         }

         System.out.println("Document deleted successfully");

      }catch(Exception e){

                       System.err.println( e.getClass().getName() + ": " + e.getMessage() );

                    }

   }

}

 

编译运行以上程序,输出结果如下:

 

Connect to database successfully

Authentication: true

Collection mycol selected successfully

Document deleted successfully

 

你还可以使用 save(), limit(), skip(), sort() 等方法来操作MongoDB数据库。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6MongoDB PHP 扩展

本教程将向大家介绍如何在LinuxwindowMac平台上安装MongoDB扩展。


6.1 Linux上安装 MongoDB PHP扩展

6.1.1 在终端上安装

你可以在linux中执行以下命令来安装MongoDB PHP 扩展驱动

$ sudo pecl install mongo

使用phppecl安装命令必须保证网络连接可用以及root权限。

安装手册

如果你想通过源码来编译扩展驱动。你必须手动编译源码包,这样做的好是最新修正的bug包含在源码包中。

你可以在Github上下载MongoDB PHP驱动包。访问github网站然后搜索"mongo php driver"(下载地址:https://github.com/mongodb/mongo-php-driver),下载该源码包,然后执行以下命令:

$ tar zxvf mongodb-mongodb-php-driver-<commit_id>.tar.gz
$ cd mongodb-mongodb-php-driver-<commit_id>
$ phpize
$ ./configure
$ sudo make install

如果你的php是自己编译的,则安装方法如下(假设是编译在/usr/local/php目录中)

$ tar zxvf mongodb-mongodb-php-driver-<commit_id>.tar.gz
$ cd mongodb-mongodb-php-driver-<commit_id>
$ /usr/local/php/bin/phpize
$ ./configure --with-php-config=/usr/local/php/bin/php-config
$ sudo make install

执行以上命令后,你需要修改php.ini文件,在php.ini文件中添加mongo配置,配置如下:

extension=mongo.so

注意:你需要指明 extension_dir 配置项的路径。


6.2 window上安装 MongoDB PHP扩展

Github上已经提供了用于window平台的预编译php mongodb驱动二进制包(下载地址: https://s3.amazonaws.com/drivers.mongodb.org/php/index.html),你可以下载与你php对应的版本,但是你需要注意以下几点问题:

打开php配置文件 php.ini 添加以下配置:

extension=php_mongo.dll

重启服务器。

通过浏览器访问phpinfo,如果安装成功,就会看到类型以下的信息:

mongo-php-driver-installed-windows


6.3 MAC中安装MongoDB PHP扩展驱动

你可以使用'autoconf'安装MongoDB PHP扩展驱动。

你可以使用'Xcode'安装MongoDB PHP扩展驱动。

如果你使用 XAMPP,你可以使用以下命令安装MongoDB PHP扩展驱动:

sudo /Applications/XAMPP/xamppfiles/bin/pecl install mongo

如果以上命令在XMPP或者MAMP中不起作用,你需要在Github上下载兼容的预编译包。

然后添加 'extension=mongo.so'配置到你的php.ini文件中。

 

 

7MongoDB PHP

php中使用mongodb你必须使用 mongodbphp驱动。

MongoDB PHP在各平台上的安装及驱动包下载请查看:PHP安装MongoDB扩展驱动

确保连接及选择一个数据库

为了确保正确连接,你需要指定数据库名,如果数据库在mongoDB中不存在,mongoDB会自动创建

代码片段如下:

<?php

   // 连接到mongodb

   $m = new MongoClient();

   echo "Connection to database successfully";

   // 选择一个数据库

   $db = $m->mydb;

   echo "Database mydb selected";

?>

执行以上程序,输出结果如下:

Connection to database successfully

Database mydb selected

创建集合

创建集合的代码片段如下:

<?php

   // 连接到mongodb

   $m = new MongoClient();

   echo "Connection to database successfully";

   // 选择一个数据库

   $db = $m->mydb;

   echo "Database mydb selected";

   $collection = $db->createCollection("mycol");

   echo "Collection created succsessfully";

?>

 

执行以上程序,输出结果如下:

 

Connection to database successfully

Database mydb selected

Collection created succsessfully

 

插入文档

mongoDB中使用 insert() 方法插入文档:

插入文档代码片段如下:

<?php

   // 连接到mongodb

   $m = new MongoClient();

   echo "Connection to database successfully";

   // 选择一个数据库

   $db = $m->mydb;

   echo "Database mydb selected";

   $collection = $db->mycol;

   echo "Collection selected succsessfully";

   $document = array(

      "title" => "MongoDB",

      "description" => "database",

      "likes" => 100,

      "url" => "http://www.w3cschool.cc/mongodb/",

      "by", "w3cschool.cc"

   );

   $collection->insert($document);

   echo "Document inserted successfully";

?>

执行以上程序,输出结果如下:

 

Connection to database successfully

Database mydb selected

Collection selected succsessfully

Document inserted successfully

 

查找文档

使用find() 方法来读取集合中的文档。

读取使用文档的代码片段如下:

<?php

   // 连接到mongodb

   $m = new MongoClient();

   echo "Connection to database successfully";

   // 选择一个数据库

   $db = $m->mydb;

   echo "Database mydb selected";

   $collection = $db->mycol;

   echo "Collection selected succsessfully";

 

   $cursor = $collection->find();

   // 迭代显示文档标题

   foreach ($cursor as $document) {

      echo $document["title"] . "\n";

   }

?>

 

执行以上程序,输出结果如下:

 

Connection to database successfully

Database mydb selected

Collection selected succsessfully

{

   "title": "MongoDB"

}

 

更新文档

 

使用 update() 方法来更新文档。

 

以下实例将更新文档中的标题为' MongoDB Tutorial' 代码片段如下:

 

<pre>

<?php

   // 连接到mongodb

   $m = new MongoClient();

   echo "Connection to database successfully";

   // 选择一个数据库

   $db = $m->mydb;

   echo "Database mydb selected";

   $collection = $db->mycol;

   echo "Collection selected succsessfully";

 

   // 更新文档

   $collection->update(array("title"=>"MongoDB"), array('$set'=>array("title"=>"MongoDB Tutorial")));

   echo "Document updated successfully";

   // 显示更新后的文档

   $cursor = $collection->find();

   // 循环显示文档标题

   echo "Updated document";

   foreach ($cursor as $document) {

      echo $document["title"] . "\n";

   }

?>

 

执行以上程序,输出结果如下:

 

Connection to database successfully

Database mydb selected

Collection selected succsessfully

Document updated successfully

Updated document

{

   "title": "MongoDB Tutorial"

}

 

删除文档

 

使用 remove() 方法来删除文档。

 

以下实例中我们将移除 'title' 'MongoDB Tutorial' 的数据记录。, 代码片段如下:

 

<?php

   // 连接到mongodb

   $m = new MongoClient();

   echo "Connection to database successfully";

   // 选择一个数据库

   $db = $m->mydb;

   echo "Database mydb selected";

   $collection = $db->mycol;

   echo "Collection selected succsessfully";

  

   // 移除文档

   $collection->remove(array("title"=>"MongoDB Tutorial"),false);

   echo "Documents deleted successfully";

  

   // 显示可用文档数据

   $cursor = $collection->find();

   // iterate cursor to display title of documents

   echo "Updated document";

   foreach ($cursor as $document) {

      echo $document["title"] . "\n";

   }

?>

 

执行以上程序,输出结果如下:

 

Connection to database successfully

Database mydb selected

Collection selected succsessfully

Documents deleted successfully

 

除了以上实例外,在php中你还可以使用findOne(), save(), limit(), skip(), sort()等方法来操作Mongodb数据库。

 

 

 

8MongoDB 高级

8.1 MongoDB 关系

 

MongoDB 的关系表示多个文档之间在逻辑上的相互联系。

 

文档间可以通过嵌入和引用来建立联系。

 

MongoDB 中的关系可以是:

 

    1:1 (11)

    1: N (1对多)

    N: 1 (多对1)

    N: N (多对多)

 

接下来我们来考虑下用户与用户地址的关系。

 

一个用户可以有多个地址,所以是一对多的关系。

 

以下是 user 文档的简单结构:

 

{

   "_id":ObjectId("52ffc33cd85242f436000001"),

   "name": "Tom Hanks",

   "contact": "987654321",

   "dob": "01-01-1991"

}

 

以下是 address 文档的简单结构:

 

{

   "_id":ObjectId("52ffc4a5d85242602e000000"),

   "building": "22 A, Indiana Apt",

   "pincode": 123456,

   "city": "Los Angeles",

   "state": "California"

}

 

嵌入式关系

 

使用嵌入式方法,我们可以把用户地址嵌入到用户的文档中:

 

   "_id":ObjectId("52ffc33cd85242f436000001"),

   "contact": "987654321",

   "dob": "01-01-1991",

   "name": "Tom Benzamin",

   "address": [

      {

         "building": "22 A, Indiana Apt",

         "pincode": 123456,

         "city": "Los Angeles",

         "state": "California"

      },

      {

         "building": "170 A, Acropolis Apt",

         "pincode": 456789,

         "city": "Chicago",

         "state": "Illinois"

      }]

}

 

以上数据保存在单一的文档中,可以比较容易的获取很维护数据。 你可以这样查询用户的地址:

 

>db.users.findOne({"name":"Tom Benzamin"},{"address":1})

 

注意:以上查询中 db users 表示数据库和集合。

 

这种数据结构的缺点是,如果用户和用户地址在不断增加,数据量不断变大,会影响读写性能。

 

引用式关系

 

引用式关系是设计数据库时经常用到的方法,这种方法把用户数据文档和用户地址数据文档分开,通过引用文档的 id 字段来建立关系。

 

{

   "_id":ObjectId("52ffc33cd85242f436000001"),

   "contact": "987654321",

   "dob": "01-01-1991",

   "name": "Tom Benzamin",

   "address_ids": [

      ObjectId("52ffc4a5d85242602e000000"),

      ObjectId("52ffc4a5d85242602e000001")

   ]

}

 

以上实例中,用户文档的 address_ids 字段包含用户地址的对象idObjectId)数组。

 

我们可以读取这些用户地址的对象idObjectId)来获取用户的详细地址信息。

 

这种方法需要两次查询,第一次查询用户地址的对象idObjectId),第二次通过查询的id获取用户的详细地址信息。

 

>var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})

>var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})

 

 

 

8.2 MongoDB 数据库引用

 

在上一章节MongoDB关系中我们提到了MongoDB的引用来规范数据结构文档。

 

MongoDB 引用有两种:

 

    手动引用(Manual References

    DBRefs

 

DBRefs vs 手动引用

 

考虑这样的一个场景,我们在不同的集合中 (address_home, address_office, address_mailing, )存储不同的地址(住址,办公室地址,邮件地址等)。

 

这样,我们在调用不同地址时,也需要指定集合,一个文档从多个集合引用文档,我们应该使用 DBRefs

使用 DBRefs

 

DBRef的形式:

 

{ $ref : , $id : , $db :  }

 

三个字段表示的意义为:

 

    $ref:集合名称

    $id:引用的id

    $db:数据库名称,可选参数

 

以下实例中用户数据文档使用了 DBRef, 字段 address

 

{

   "_id":ObjectId("53402597d852426020000002"),

   "address": {

   "$ref": "address_home",

   "$id": ObjectId("534009e4d852427820000002"),

   "$db": "w3cschoolcc"},

   "contact": "987654321",

   "dob": "01-01-1991",

   "name": "Tom Benzamin"

}

 

address DBRef 字段指定了引用的地址文档是在 address_home 集合下的 w3cschoolcc 数据库,id 534009e4d852427820000002

 

以下代码中,我们通过指定 $ref 参数(address_home 集合)来查找集合中指定id的用户地址信息:

 

>var user = db.users.findOne({"name":"Tom Benzamin"})

>var dbRef = user.address

>db[dbRef.$ref].findOne({"_id":(dbRef.$id)})

 

以上实例返回了 address_home 集合中的地址数据:

 

{

   "_id" : ObjectId("534009e4d852427820000002"),

   "building" : "22 A, Indiana Apt",

   "pincode" : 123456,

   "city" : "Los Angeles",

   "state" : "California"

}

 

8.3 MongoDB 覆盖索引查询

 

官方的MongoDB的文档中说明,覆盖查询是以下的查询:

 

    所有的查询字段是索引的一部分

    所有的查询返回字段在同一个索引中

 

由于所有出现在查询中的字段是索引的一部分, MongoDB 无需在整个数据文档中检索匹配查询条件和返回使用相同索引的查询结果。

 

因为索引存在于RAM中,从索引中获取数据比通过扫描文档读取数据要快得多。

使用覆盖索引查询

 

为了测试盖索引查询,使用以下 users 集合:

 

{

   "_id": ObjectId("53402597d852426020000002"),

   "contact": "987654321",

   "dob": "01-01-1991",

   "gender": "M",

   "name": "Tom Benzamin",

   "user_name": "tombenzamin"

}

 

我们在 users 集合中创建联合索引,字段为 gender user_name :

 

>db.users.ensureIndex({gender:1,user_name:1})

 

现在,该索引会覆盖以下查询:

 

>db.users.find({gender:"M"},{user_name:1,_id:0})

 

也就是说,对于上述查询,MongoDB的不会去数据库文件中查找。相反,它会从索引中提取数据,这是非常快速的数据查询。

 

由于我们的索引中不包括 _id 字段,_id在查询中会默认返回,我们可以在MongoDB的查询结果集中排除它。

 

下面的实例没有排除_id,查询就不会被覆盖:

 

>db.users.find({gender:"M"},{user_name:1})

 

最后,如果是以下的查询,不能使用覆盖索引查询:

 

    所有索引字段是一个数组

所有索引字段是一个子文档

 

8.4 MongoDB 查询分析

 

MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。

 

MongoDB 查询分析常用函数有:explain() hint()

使用 explain()

 

explain 操作提供了查询信息,使用索引及查询统计等。有利于我们对索引的优化。

 

接下来我们在 users 集合中创建 gender user_name 的索引:

 

>db.users.ensureIndex({gender:1,user_name:1})

</p>

<p>现在在查询语句中使用 explain </p>

<pre>

>db.users.find({gender:"M"},{user_name:1,_id:0}).explain()

 

以上的 explain() 查询返回如下结果:

 

{

   "cursor" : "BtreeCursor gender_1_user_name_1",

   "isMultiKey" : false,

   "n" : 1,

   "nscannedObjects" : 0,

   "nscanned" : 1,

   "nscannedObjectsAllPlans" : 0,

   "nscannedAllPlans" : 1,

   "scanAndOrder" : false,

   "indexOnly" : true,

   "nYields" : 0,

   "nChunkSkips" : 0,

   "millis" : 0,

   "indexBounds" : {

      "gender" : [

         [

            "M",

            "M"

         ]

      ],

      "user_name" : [

         [

            {

               "$minElement" : 1

            },

            {

               "$maxElement" : 1

            }

         ]

      ]

   }

}

 

现在,我们看看这个结果集的字段:

 

    indexOnly: 字段为 true ,表示我们使用了索引。

    cursor:因为这个查询使用了索引,MongoDB中索引存储在B树结构中,所以这是也使用了BtreeCursor类型的游标。如果没有使用索引,游标的类型是BasicCursor。这个键还会给出你所使用的索引的名称,你通过这个名称可以查看当前数据库下的system.indexes集合(系统自动创建,由于存储索引信息,这个稍微会提到)来得到索引的详细信息。

    n:当前查询返回的文档数量。

    nscanned/nscannedObjects:表明当前这次查询一共扫描了集合中多少个文档,我们的目的是,让这个数值和返回文档的数量越接近越好。

    millis:当前查询所需时间,毫秒数。

    indexBounds:当前查询具体使用的索引。

 

使用 hint()

 

虽然MongoDB查询优化器一般工作的很不错,但是也可以使用hints来强迫MongoDB使用一个指定的索引。

 

这种方法某些情形下会提升性能。 一个有索引的collection并且执行一个多字段的查询(一些字段已经索引了)

 

如下查询实例指定了使用 gender user_name 索引字段来查询:

 

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})

 

可以使用 explain() 函数来分析以上查询:

 

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()

 

 

8.5 MongoDB 原子操作

 

mongodb不支持事务,所以,在你的项目中应用时,要注意这点。无论什么设计,都不要要求mongodb保证数据的完整性。

 

但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操作。

 

所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查询到的文档没有保存完整的情况。

原子操作数据模型

 

考虑下面的例子,图书馆的书籍及结账信息。

 

实例说明了在一个相同的文档中如何确保嵌入字段关联原子操作(update:更新)的字段是同步的。

 

book = {

          _id: 123456789,

          title: "MongoDB: The Definitive Guide",

          author: [ "Kristina Chodorow", "Mike Dirolf" ],

          published_date: ISODate("2010-09-24"),

          pages: 216,

          language: "English",

          publisher_id: "oreilly",

          available: 3,

          checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]

        }

 

你可以使用 db.collection.findAndModify() 方法来判断书籍是否可结算并更新新的结算信息。

 

在同一个文档中嵌入的 available checkout 字段来确保这些字段是同步更新的:

 

db.books.findAndModify ( {

   query: {

            _id: 123456789,

            available: { $gt: 0 }

          },

   update: {

             $inc: { available: -1 },

             $push: { checkout: { by: "abc", date: new Date() } }

           }

} )

 

原子操作常用命令

$set

 

用来指定一个键并更新键值,若键不存在并创建。

 

{ $set : { field : value } }

 

$unset

 

用来删除一个键。

 

{ $unset : { field : 1} }

 

$inc

 

$inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。

 

{ $inc : { field : value } }

 

$push

 

用法:

 

{ $push : { field : value } }

 

value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。

$pushAll

 

$push,只是一次可以追加多个值到一个数组字段内。

 

{ $pushAll : { field : value_array } }

 

$pull

 

从数组field内删除一个等于value值。

 

{ $pull : { field : _value } }

 

$addToSet

 

增加一个值到数组内,而且只有当这个值不在数组内才增加。

$pop

 

删除数组的第一个或最后一个元素

 

{ $pop : { field : 1 } }

 

$rename

 

修改字段名称

 

{ $rename : { old_field_name : new_field_name } }

 

$bit

 

位操作,integer类型

 

{$bit : { field : {and : 5}}}

 

偏移操作符

 

> t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }

 

> t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true )

 

> t.find() { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }

 

8.6 MongoDB 高级索引

 

考虑以下文档集合(users :

 

{

   "address": {

      "city": "Los Angeles",

      "state": "California",

      "pincode": "123"

   },

   "tags": [

      "music",

      "cricket",

      "blogs"

   ],

   "name": "Tom Benzamin"

}

 

以上文档包含了 address 子文档和 tags 数组。

索引数组字段

 

假设我们基于标签来检索用户,为此我们需要对集合中的数组 tags 建立索引。

 

在数组中创建索引,需要对数组中的每个字段依次建立索引。所以在我们为数组 tags 创建索引时,会为 musiccricketblogs三个值建立单独的索引。

 

使用以下命令创建数组索引:

 

>db.users.ensureIndex({"tags":1})

 

创建索引后,我们可以这样检索集合的 tags 字段:

 

>db.users.find({tags:"cricket"})

 

为了验证我们使用使用了索引,可以使用 explain 命令:

 

>db.users.find({tags:"cricket"}).explain()

 

以上命令执行结果中会显示 "cursor" : "BtreeCursor tags_1" ,则表示已经使用了索引。

索引子文档字段

 

假设我们需要通过citystatepincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。

 

为子文档的三个字段创建索引,命令如下:

 

>db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1})

 

一旦创建索引,我们可以使用子文档的字段来检索数据:

 

>db.users.find({"address.city":"Los Angeles"})  

 

记住查询表达式必须遵循指定的索引的顺序。所以上面创建的索引将支持以下查询:

 

>db.users.find({"address.city":"Los Angeles","address.state":"California"})

 

同样支持以下查询:

 

>db.users.find({"address.city":"LosAngeles","address.state":"California","address.pincode":"123"})

 

 

 

 

8.7 MongoDB 索引限制

 

额外开销

 

每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。所以,如果你很少对集合进行读取操作,建议不使用索引。

 

内存(RAM)使用

 

由于索引是存储在内存(RAM),你应该确保该索引的大小不超过内存的限制。

 

如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。

查询限制

 

索引不能被以下的查询使用:

 

    正则表达式及非操作符,如 $nin, $not, 等。

    算术运算符,如 $mod, 等。

    $where 子句

 

所以,检测你的语句是否使用索引是一个好的习惯,可以用explain来查看。

索引键限制

 

2.6版本开始,如果现有的索引字段的值超过索引键的限制,MongoDB中不会创建索引。

 

插入文档超过索引键限制

 

如果文档的索引字段值超过了索引键的限制,MongoDB不会将任何文档转换成索引的集合。与mongorestoremongoimport工具类似。

 

最大范围

 

    集合中索引不能超过64

    索引名的长度不能超过125个字符

    一个复合索引最多可以有31个字段

 

 

 

8.8 MongoDB ObjectId

 

在前面几个章节中我们已经使用了MongoDB 的对象 Id(ObjectId)

 

在本章节中,我们将了解的ObjectId的结构。

 

ObjectId 是一个12字节 BSON 类型数据,有以下格式:

 

    4个字节表示时间戳

    接下来的3个字节是机器标识码

    紧接的两个字节由进程id组成(PID

    最后三个字节是随机数。

 

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任何类型的,默认是个ObjectId对象。

 

在一个集合里面,每个集合都有唯一的"_id"值,来确保集合里面每个文档都能被唯一标识。

 

MongoDB采用ObjectId,而不是其他比较常规的做法(比如自动增加的主键)的主要原因,因为在多个 服务器上同步自动增加主键值既费力还费时。

创建信的ObjectId

 

使用以下代码生成新的ObjectId

 

>newObjectId = ObjectId()

 

上面的语句返回以下唯一生成的id

 

ObjectId("5349b4ddd2781d08c09890f3")

 

你也可以使用生成的id来取代MongoDB自动生成的ObjectId

 

>myObjectId = ObjectId("5349b4ddd2781d08c09890f4")

 

创建文档的时间戳

 

由于 ObjectId 中存储了 4 个字节的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间:

 

>ObjectId("5349b4ddd2781d08c09890f4").getTimestamp()

 

以上代码将返回 ISO 格式的文档创建时间:

 

ISODate("2014-04-12T21:49:17Z")

 

ObjectId 转换为字符串

 

在某些情况下,您可能需要将ObjectId转换为字符串格式。你可以使用下面的代码:

 

>new ObjectId.str

 

以上代码将返回Guid格式的字符串::

 

5349b4ddd2781d08c09890f3

 

 

 

 

 

 

 

8.9 MongoDB Map Reduce

 

Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。

 

MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用。

 

MapReduce 命令

 

以下是MapReduce的基本语法:

 

>db.collection.mapReduce(

   function() {emit(key,value);},  //map 函数

   function(key,values) {return reduceFunction},   //reduce 函数

   {

      out: collection,

      query: document,

      sort: document,

      limit: number

   }

)

 

使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, key value 传递给 Reduce 函数进行处理。

 

Map 函数必须调用 emit(key, value) 返回键值对。

 

参数说明:

 

    map :映射函数 (生成键值对序列,作为 reduce 函数参数)

    reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。

    out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)

    query 一个筛选条件,只有满足条件的文档才会调用map函数。(querylimitsort可以随意组合)

    sort limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制

    limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)

 

使用 MapReduce

 

考虑以下文档结构存储用户的文章,文档存储了用户的 user_name 和文章的 status字段:

 

{

   "post_text": "w3cschool.cc 菜鸟教程,最全的技术文档。",

   "user_name": "mark",

   "status":"active"

}

 

现在,我们将在 posts 集合中使用 mapReduce 函数来选取已发布的文章,并通过user_name分组,计算每个用户的文章数:

 

>db.posts.mapReduce(

   function() { emit(this.user_id,1); },

   function(key, values) {return Array.sum(values)},

      { 

         query:{status:"active"}, 

         out:"post_total"

      }

)

 

以上 mapReduce 输出结果为:

 

{

   "result" : "post_total",

   "timeMillis" : 9,

   "counts" : {

      "input" : 4,

      "emit" : 4,

      "reduce" : 2,

      "output" : 2

   },

   "ok" : 1,

}

 

结果表明,共有4个符合查询条件(status:"active")的文档, map函数中生成了4个键值对文档,最后使用reduce函数将相同的键值分为两组。

 

具体参数说明:

 

    result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。

    timeMillis:执行花费的时间,毫秒为单位

    input:满足条件被发送到map函数的文档个数

    emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量

    ouput:结果集合中的文档个数(count对调试非常有帮助)

    ok:是否成功,成功为1

    err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大

 

使用 find 操作符来查看 mapReduce 的查询结果:

 

>db.posts.mapReduce(

   function() { emit(this.user_id,1); },

   function(key, values) {return Array.sum(values)},

      { 

         query:{status:"active"}, 

         out:"post_total"

      }

).find()

 

以上查询显示如下结果,两个用户 tom mark 有两个发布的文章:

 

{ "_id" : "tom", "value" : 2 }

{ "_id" : "mark", "value" : 2 }

 

用类似的方式,MapReduce可以被用来构建大型复杂的聚合查询。

 

Map函数和Reduce函数可以使用 JavaScript 来实现,是的MapReduce的使用非常灵活和强大。

 

 

 

8.10 MongoDB 全文检索

 

全文检索对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。

 

这个过程类似于通过字典中的检索字表查字的过程。

 

MongoDB 2.4 版本开始支持全文检索,目前支持15种语言(暂时不支持中文)的全文索引。

 

    danish

    dutch

    english

    finnish

    french

    german

    hungarian

    italian

    norwegian

    portuguese

    romanian

    russian

    spanish

    swedish

    turkish

 

启用全文检索

 

MongoDB 2.6 版本以后是默认开启全文检索的,如果你使用之前的版本,你需要使用以下代码来启用全文检索:

 

>db.adminCommand({setParameter:true,textSearchEnabled:true})

 

或者使用命令:

 

mongod --setParameter textSearchEnabled=true

 

创建全文索引

 

考虑以下 posts 集合的文档数据,包含了文章内容(post_text)及标签(tags)

 

{

   "post_text": "enjoy the mongodb articles on w3cschool.cc",

   "tags": [

      "mongodb",

      "w3cschool"

   ]

}

 

我们可以对 post_text 字段建立全文索引,这样我们可以搜索文章内的内容:

 

>db.posts.ensureIndex({post_text:"text"})

 

使用全文索引

 

现在我们已经对 post_text 建立了全文索引,我们可以搜索文章中的关键词w3cschool.cc

 

>db.posts.find({$text:{$search:"w3cschool.cc"}})

 

以下命令返回了如下包含w3cschool.cc关键词的文档数据:

 

{

   "_id" : ObjectId("53493d14d852429c10000002"),

   "post_text" : "enjoy the mongodb articles on w3cschool.cc",

   "tags" : [ "mongodb", "w3cschool" ]

}

{

   "_id" : ObjectId("53493d1fd852429c10000003"),

   "post_text" : "writing tutorials on w3cschool.cc",

   "tags" : [ "mongodb", "tutorial" ]

}

 

如果你使用的是旧版本的MongoDB,你可以使用以下命令:

 

>db.posts.runCommand("text",{search:" w3cschool.cc"})

 

使用全文索引可以提高搜索效率。

删除全文索引

 

删除已存在的全文索引,可以使用 find 命令查找索引名:

 

>db.posts.getIndexes()

 

通过以上命令获取索引名,本例的索引名为post_text_text,执行以下命令来删除索引:

 

>db.posts.dropIndex("post_text_text")

 

 

 

 

8.11 MongoDB 正则表达式

 

正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。

 

许多程序设计语言都支持利用正则表达式进行字符串操作。

 

MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。

 

MongoDB使用PCRE (Perl Compatible Regular Expression) 作为正则表达式语言。

 

不同于全文检索,我们使用正则表达式不需要做任何配置。

 

考虑以下 posts 集合的文档结构,该文档包含了文章内容和标签:

 

{

   "post_text": "enjoy the mongodb articles on tutorialspoint",

   "tags": [

      "mongodb",

      "tutorialspoint"

   ]

}

 

使用正则表达式

 

以下命令使用正则表达式查找包含 w3cschool.cc 字符串的文章:

 

>db.posts.find({post_text:{$regex:"w3cschool.cc"}})

 

以上查询也可以写为:

 

>db.posts.find({post_text:/w3cschool.cc/})

 

不区分大小写的正则表达式

 

如果检索需要不区分大小写,我们可以设置 $options $i

 

以下命令将查找不区分大小写的字符串 w3cschool.cc

 

>db.posts.find({post_text:{$regex:"w3cschool.cc",$options:"$i"}})

 

集合中会返回所有包含字符串 w3cschool.cc 的数据,且不区分大小写:

 

{

   "_id" : ObjectId("53493d37d852429c10000004"),

   "post_text" : "hey! this is my post on  W3Cschool.cc",

   "tags" : [ "tutorialspoint" ]

}

 

数组元素使用正则表达式

 

我们还可以在数组字段中使用正则表达式来查找内容。 这在标签的实现上非常有用,如果你需要查找包含以 tutorial 开头的标签数据(tutorial tutorials tutorialpoint tutorialphp) 你可以使用以下代码:

 

>db.posts.find({tags:{$regex:"tutorial"}})

 

优化正则表达式查询

 

    如果你的文档中字段设置了索引,那么使用索引相比于正则表达式匹配查找所有的数据查询速度更快。

 

    如果正则表达式是前缀表达式,所有匹配的数据将以指定的前缀字符串为开始。例如: 如果正则表达式为 ^tut ,查询语句将查找以 tut 为开头的字符串。

 

这里面使用正则表达式有两点需要注意:

 

正则表达式中使用变量。一定要使用eval将组合的字符串进行转换,不能直接将字符串拼接后传入给表达式。否则没有报错信息,只是结果为空!实例如下:

 

var name=eval("/" + 变量值key +"/i");

 

以下是模糊查询包含title关键词, 且不区分大小写:

 

title:eval("/"+title+"/i")    // 等同于 title:{$regex:title,$Option:"$i"}  

 

 

 

 

8.12 MongoDB 管理工具: Rockmongo

 

RockMongoPHP5写的一个MongoDB管理工具。

 

通过 Rockmongo 你可以管理 MongoDB服务,数据库,集合,文档,索引等等。

 

它提供了非常人性化的操作。类似 phpMyAdminPHP开发的MySql管理工具)。

 

Rockmongo 下载地址:http://rockmongo.com/downloads Rockmongo 管理工具

简介

 

主要特征:

 

    使用宽松的New BSD License协议

    速度快,安装简单

    支持多语言(目前提供中文、英文、日文、巴西葡萄牙语、法语、德语、俄语、意大利语)

    系统

        可以配置多个主机,每个主机可以有多个管理员

        需要管理员密码才能登入操作,确保数据库的安全性

    服务器

        服务器信息 (WEB服务器, PHP, PHP.ini相关指令 ...)

        状态

        数据库信息

    数据库

        查询,创建和删除

        执行命令和Javascript代码

        统计信息

    集合(相当于表)

        强大的查询工具

        读数据,写数据,更改数据,复制数据,删除数据

        查询、创建和删除索引

        清空数据

        批量删除和更改数据

        统计信息

    GridFS

        查看分块

        下载文件

 

安装

需求

 

    一个能运行PHPWeb服务器,比如Apache Httpd, Nginx ...

    PHP - 需要PHP v5.1.6或更高版本,需要支持SESSION

        为了能连接MongoDB,你需要安装php_mongo扩展

 

快速安装

 

    下载安装包

    解压到你的网站目录下

    用编辑器打开config.php,修改host, port, admins等参数

    在浏览器中访问index.php,比如说:http://localhost/rockmongo/index.php

    使用用户名和密码登录,默认为"admin""admin"

    开始玩转MongoDB!

 

参考文章:http://rockmongo.com/wiki/introduction?lang=zh_cn

 

 

8.13 MongoDB GridFS

 

GridFS 用于存储和恢复那些超过16MBSON文件限制)的文件(如:图片、音频、视频等)

 

GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。

 

GridFS 可以更好的存储大于16M的文件。

 

GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。

 

GridFS 用两个集合来存储一个文件:fs.filesfs.chunks

 

每个文件的实际内容被存在chunks(二进制数据),和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。

 

以下是简单的 fs.files 集合文档:

 

{

   "filename": "test.txt",

   "chunkSize": NumberInt(261120),

   "uploadDate": ISODate("2014-04-13T11:32:33.557Z"),

   "md5": "7b762939321e146569b07f72c62cca4f",

   "length": NumberInt(646)

}

 

以下是简单的 fs.chunks 集合文档:

 

{

   "files_id": ObjectId("534a75d19f54bfec8a2fe44b"),

   "n": NumberInt(0),

   "data": "Mongo Binary Data"

}

 

GridFS 添加文件

 

现在我们使用 GridFS put 命令来存储 mp3 文件。 调用 MongoDB 安装目录下bin mongofiles.exe工具。

 

打开命令提示符,进入到MongoDB的安装目录的bin目录中,找到mongofiles.exe,并输入下面的代码:

 

>mongofiles.exe -d gridfs put song.mp3

 

GridFS 是存储文件的数据名称。如果不存在该数据库,MongoDB会自动创建。Song.mp3 是音频文件名。

 

使用以下命令来查看数据库中文件的文档:

 

>db.fs.files.find()

 

以上命令执行后返回以下文档数据:

 

{

   _id: ObjectId('534a811bf8b4aa4d33fdf94d'),

   filename: "song.mp3",

   chunkSize: 261120,

   uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41",

   length: 10401959

}

 

我们可以看到 fs.chunks 集合中所有的区块,以下我们得到了文件的 _id 值,我们可以根据这个 _id 获取区块(chunk)的数据:

 

>db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})

 

以上实例中,查询返回了 40 个文档的数据,意味着mp3文件被存储在40个区块中。

 

 

 

8.14 MongoDB 固定集合(Capped Collections

 

MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头部的元素!

创建固定集合

 

我们通过createCollection来创建一个固定集合,且capped选项设置为true

 

>db.createCollection("cappedLogCollection",{capped:true,size:10000})

 

还可以指定文档个数,加上max:1000属性:

 

>db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})

 

判断集合是否为固定集合:

 

>db.cappedLogCollection.isCapped()

 

如果需要将已存在的集合转换为固定集合可以使用以下命令:

 

>db.runCommand({"convertToCapped":"posts",size:10000})

 

以上代码将我们已存在的 posts 集合转换为固定集合。

固定集合查询

 

固定集合文档按照插入顺序储存的,默认情况下查询就是按照插入顺序返回的,也可以使用$natural调整返回顺序。

 

>db.cappedLogCollection.find().sort({$natural:-1})

 

固定集合的功能特点

 

可以插入及更新,但更新不能超出collection的大小,否则更新失败,不允许删除,但是可以调用drop()删除集合中的所有行,但是drop后需要显式地重建集合。

 

32位机子上一个cappped collection的最大值约为482.5M,64位上只受系统文件大小的限制。

固定集合属性及用法

属性

 

    属性1:对固定集合进行插入速度极快

    属性2:按照插入顺序的查询输出速度极快

    属性3:能够在插入最新数据时,淘汰最早的数据

 

用法

 

    用法1:储存日志信息

    用法2:缓存一些少量的文档

 

8.15 MongoDB 自动增长

 

MongoDB 没有像 SQL 一样有自动增长的功能, MongoDB _id 是系统自动生成的12字节唯一标识。

 

但在某些情况下,我们可能需要实现 ObjectId 自动增长功能。

 

由于 MongoDB 没有实现这个功能,我们可以通过编程的方式来实现,以下我们将在 counters 集合中实现_id字段自动增长。

使用 counters 集合

 

考虑以下 products 文档。我们希望 _id 字段实现 1,2,3,4 n 的自动增长功能。

 

{

  "_id":1,

  "product_name": "Apple iPhone",

  "category": "mobiles"

}

 

为此,创建 counters 集合,序列字段值可以实现自动长:

 

>db.createCollection("counters")

 

现在我们向 counters 集合中插入以下文档,使用 productid 作为 key:

 

{

  "_id":"productid",

  "sequence_value": 0

}

 

sequence_value 字段是序列通过自动增长后的一个值。

 

使用以下命令插入 counters 集合的序列文档中:

 

>db.counters.insert({_id:"productid",sequence_value:0})

 

创建 Javascript 函数

 

现在,我们创建函数 getNextSequenceValue 来作为序列名的输入, 指定的序列会自动增长 1 并返回最新序列值。在本文的实例中序列名为 productid

 

>function getNextSequenceValue(sequenceName){

   var sequenceDocument = db.counters.findAndModify(

      {

         query:{_id: sequenceName },

         update: {$inc:{sequence_value:1}},

         new:true

      });

   return sequenceDocument.sequence_value;

}

 

使用 Javascript 函数

 

接下来我们将使用 getNextSequenceValue 函数创建一个新的文档, 并设置文档 _id 自动为返回的序列值:

 

>db.products.insert({

   "_id":getNextSequenceValue("productid"),

   "product_name":"Apple iPhone",

   "category":"mobiles"})

 

>db.products.insert({

   "_id":getNextSequenceValue("productid"),

   "product_name":"Samsung S3",

   "category":"mobiles"})

 

就如你所看到的,我们使用 getNextSequenceValue 函数来设置 _id 字段。

 

为了验证函数是否有效,我们可以使用以下命令读取文档:

 

>db.prodcuts.find()

 

以上命令将返回以下结果,我们发现 _id 字段是自增长的:

 

{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}

 

{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }