MongoDB笔记
NoSQL简介
Not Only SQL
为了处理庞大的数据而产生
大多数是分布式的,性能高
CAP定理
一个分布式系统不可能同时满足三个需求,最多同时满足两个
- Consistency 一致性 所有节点在同一时间具有相同的数据
- Availability 可用性 每个请求无论成功或失败都有响应
- Partition tolerance 分隔容忍 系统中任意信息的丢失不会影响系统的继续运作
CA:RDBMS
CP:MongoDB,HBase,Redis
AP:CouchDB,Cassandra,DynamoDB,Riak
丢失信息后,由于不存在数据库中的关系(关系的建立在程序一端),
不影响数据库的运行
ACID vs BASE
传统数据库与NoSQL数据库讲究的不同
ACID | BASE |
---|---|
原子性(Atomicity) | 基本可用(Basically Available) |
一致性(Consistency) | 软状态/柔性事务(Soft state) |
隔离性(Isolation) | 最终一致性 (Eventual consistency) |
持久性 (Durable) |
其中最终一致性就是将关系的赋予放在程序中,
最终结果与传统数据库相同
分类
类型 | 部分代表 | 特点 |
---|---|---|
列存储 | Hbase Cassandra Hypertable | 顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。 |
文档存储 | MongoDB CouchDB | 文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有机会对某些字段建立索引,实现关系数据库的某些功能。 |
key-value存储 | Tokyo Cabine t / Tyrant Berkeley DB MemcacheDB Redis | 可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能) |
图存储 | Neo4J FlockDB | 图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。 |
对象存储 | db4o Versant | 通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。 |
xml数据库 | Berkeley DB XML BaseX | 高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。 |
MongoDB简介
- 2009年2月首次推出
- 开源
- C++编写
- 基于分布式文件存储(高负载时添加节点以保证性能)
- 数据为键值对,类似JSON,称为BSON(Binary),大小限制16M
- 检索,插入等全部依赖于键值对,以及为了扩展而使用的提示符
- 特点是介于关系型数据库与非关系型数据库之间(非关系型数据库入门之选)
安装
windows
-
下载安装包安装
-
建立需要的文件夹和配置文件
配置文件1
2
3
4
5systemLog:
destination: file
path: c:\data\log\mongod.log
storage:
dbPath: c:\data\db -
使用配置文件启动服务
1
C:\mongodb\bin\mongod.exe --config "C:\mongodb\mongod.cfg" --install
-
shell管理
1
mongo
linux
-
下载解压添加PATH
-
可以使用参数启动服务
1
mongod --dbpath "/usr/local/mongodata/db"
-
shell管理
1
mongo
-
mongod Web界面
1
mongod --rest
web界面比服务端端口多1000
osx
-
一般安装
下载皆有添加path
-
brew安装
名为mongodb
支持SSL需要命令--with-opensl
开发版本需要--devel
-
运行
同其他
术语相关
对比
SQL术语 | MongoDB术语 | 说明 |
---|---|---|
database | database | 数据库 |
table | collection | 集合 |
row | document | 文档 |
column | field | 字段 |
index | index | 索引 |
table joins | 使用嵌入文档实现,但更多的是在程序中实现 | |
primary key | 主键,MongoDB自动将\~id字段设置为主键~ |
数据库
MongoDB默认数据库为"db",对应文件夹/<somewhere>/db/
相关操作:
- show dbs 查看所有的数据库
- db 显示当前数据库
- use <dbname> 使用数据库/连接数据库,没有会创建
- 命名规则:
- 全部小写
- 最多64字节
- 不能有引号,空格,句号,$,/,\,空字符
- 不能为空
- 避开保留名称
- admin 权限管理相关
- local 本地的数据
- config 用于保存分片信息
- 命名规则:
集合
相当于表
- 没有固定结构: 一条数据与其他数据可以有不同的键,但一般人为写成大致相同的
命名
- 不能含有保留字符
- 以system.开头是保留的
- 不能含有空字符
- 不能为空
Capped collections
- 固定大小的集合,因此性能好
- 列队过期(空间不足时,新的来旧的走)
- 适合日志
文档
相当于行
- 格式为JSON
- 键值对是有序的
- 区分类型和大小写
- 可以使用其他格式的数据
键的注意
- 不可以重复
- 可以使用utf-8字符
- 不能有空字符
- .和$不能轻易使用
- 下划线表示保留字段
元数据
每一个数据库的元数据都放在该数据库的system集合(系统保留集合)中
集合命名空间 | 描述 |
---|---|
dbname.system.namespaces | 列出所有名字空间。 |
dbname.system.indexes | 列出所有索引,可插入数据 |
dbname.system.profile | 包含数据库概要(profile)信息,可删除 |
dbname.system.users | 列出所有可访问数据库的用户,可修改 |
dbname.local.sources | 包含复制对端(slave)的服务器信息和状态。 |
数据类型
数据类型很多
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Array | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
Object ID | 对象 ID。用于创建文档的 ID。 |
Binary Data | 二进制数据。用于存储二进制数据。 |
Code | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
-
ObjectId
唯一主键,12字节
4字节时间戳+3字节机器标识+2字节PID+3字节随机数
有时间戳,所以并不不要为数据建立插入时间戳,可以使用objectIdObject.getTimestamp()获取 -
Timestamp
一个64位的值
32位time值,远Unix新纪元相差的秒数+32位序数
用于MongoDB内部使用,程序中用的主要是Date类型 -
Date
当前距离Unix新纪元的毫秒数,可以转换为格林尼治时间.
当然也可以在程序中使用其他功能做一个包含时间信息的字符串
数据库普通操作
连接数据库
在登录mongo shell后使用
1 | mongodb://username:password@host:port/dbName?options |
- username:password可省
- port可省,默认为27017
- dbName可省,默认为test
- option之间使用&或;隔开
option与其他数据库的设置大致相同
选项 | 描述 |
---|---|
replicaSet=name | 验证replica set的名称。 Impliesconnect=replicaSet. |
slaveOk=true(false) | true:在connect=direct模式下,驱动会连接第一台机器,即使这台服务器不是主。在connect=replicaSet模式下,驱动会发送所有的写请求到主并且把读取操作分布在其他从服务器. {br} false: 在 connect=direct模式下,驱动会自动找寻主服务器. 在connect=replicaSet 模式下,驱动仅仅连接主服务器,并且所有的读写命令都连接到主服务器 |
safe=true(false) | true:在执行更新操作之后,驱动都会发送getLastError命令来确保更新成功。(还要参考 wtimeoutMS). {br} 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. {br} false: 驱动不会添加到getLastError命令中 |
journal=true(false) | 如果设置为 true, 同步到 journal (在提交到数据库前写入到实体中). 应用于 safe=true |
connectTimeoutMS=ms | 可以打开连接的时间。 |
socketTimeoutMS=ms | 发送和接受sockets的时间。 |
为什么不是在使用mongo进入shell时就询问用户名与密码?
其他操作
- show dbs 查看所有的数据库
- use <dbName> 使用数据库,没有则创建
- db 查看当前使用的数据库
- db.dropDatabase() 删除当前数据库
- show collections 查看当前数据库所有集合
- db.createCollection(name,options)
-
options的参数有
- capped 是否固定,true时需要指定size,默认false
- autoIndexId 是否将\~id作为索引~,默认false
- size 在不是capped时好像也可以使用
- max 包含文档的最大数量
-
options使用json格式定义
举例1
db.createCollection("mycol", { capped : true, autoIndexId : true, size : 6142800, max : 10000 } )
-
- db.<collectionName>.drop() 删除集合
- db.<collectionName>.insert(document) 插入文档
- 可以在集合不存在时使用,则自动创建集合
- 可以插入同样的两条文档
- db.<collectionName>.update(<query>,<update>,<option>) 更新文档
-
query相当于where后的
-
update相当与set后的
-
options有
- upsert: 如果不存在记录,是否插入?默认false
- multi: 默认更新第一条记录,可以全部更新
- writeContern: 抛出异常的级别
-
举例
例子中将title为MongoDB 教程的所有文档的title改为MongoDB1
db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})
-
- db.<collectionName>.save() 替换文档(也算是更新)
-
默认以~id为检索条件~?
-
例子中替换~id为56064f89ade2f21f36b03136~ 的文档数据
1
2
3
4
5
6
7
8
9
10
11
12db.col.save({
"_id" : ObjectId("56064f89ade2f21f36b03136"),
"title" : "MongoDB",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "Runoob",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"NoSQL"
],
"likes" : 110
})
-
- db.<collectionName>.remove(<query>,<options>) 删除数据
- options
- justOne: 是否第一个,默认false
- writeConcern: 抛出异常的级别
- options
- db.<collectionName.find(<query>,<projection>).pretty() 检索文档
- projection: 结果中包含的键,默认全部
- pretty是为了数据易读性,非必须
- db.<collectionName>.findOne(<query>,<projection>) 检索文档,只要一个
限定语
使用诸如 $lt
等关键字表示各种操作符或者含义
-
简单四则
操作 格式 范例 RDBMS中的类似语句 等于 {<key>:<value>} db.col.find({“by”:“菜鸟教程”}).pretty() where by = ‘菜鸟教程’ 小于 {$lt:<value>} db.col.find({“likes”:{$lt:50}}).pretty() where likes < 50 小于或等于 {$lte:<value>} db.col.find({“likes”:{$lte:50}}).pretty() where likes <= 50 大于 {$gt:<value>} db.col.find({“likes”:{$gt:50}}).pretty() where likes > 50 大于或等于 {$gte:<value>} db.col.find({“likes”:{$gte:50}}).pretty() where likes >= 50 不等于 {$ne:<value>} db.col.find({“likes”:{$ne:50}}).pretty() where likes != 50 -
逻辑运算
-
AND
使用逗号间隔即可
-
OR
1
$or:[{key1:value1},{key2:value2}]
使用
1
2
3
4
5
6
7db.col.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
-
-
$type指定类型
{$type: type}
type可以是数字,也可以是type名类型 数字 备注 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 举例
1
db.col.find({"title" : {$type : 2}})
-
过滤结果
检索结果对象的方法
- db.<collectionName>.find().limit(N) 仅仅显示N条
- db.<collectionName>.find().skip(N) 跳过N条
结果还是检索结果对象,可以链式使用
- db.col.find({},{“title”:1,~id~:0}).limit(2).skip(1)?
-
排序结果
检索结果对象的方法
db.COLLECTION~NAME~.find().sort({KEY:1})- 其中1表示升序,-1表示降序
-
聚合
用于处理数据(求和,计算平均值等)
-
用法
1
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
-
group举例
数据
其中按照by~user字段来统计~,runoob.com的两个,Neo4j.com一个1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27{
_id: ObjectId(7df78ad8902c)
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: ObjectId(7df78ad8902d)
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
_id: ObjectId(7df78ad8902e)
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
},表达式中相当于新定义了一个文档的结构,
定义了新文档(结果显示用)的~id~,num~tutorial字段~
$group表示分组,$sum表示求和,1表示?1
2
3
4
5
6
7
8
9
10
11
12
13
14
15> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
"result" : [
{
"_id" : "runoob.com",
"num_tutorial" : 2
},
{
"_id" : "Neo4j",
"num_tutorial" : 1
}
],
"ok" : 1
}
>相当于SQL语句
1
select by_user, count(*) from mycol group by by_user
-
其他操作符
表达式 描述 实例 $sum 计算总和。 db.mycol.aggregate([{$group : {\~id~ : “$by\~user~”, num\~tutorial~ : {$sum : “$likes”}}}]) $avg 计算平均值 db.mycol.aggregate([{$group : {\~id~ : “$by\~user~”, num\~tutorial~ : {$avg : “$likes”}}}]) $min 获取集合中所有文档对应值得最小值。 db.mycol.aggregate([{$group : {\~id~ : “$by\~user~”, num\~tutorial~ : {$min : “$likes”}}}]) $max 获取集合中所有文档对应值得最大值。 db.mycol.aggregate([{$group : {\~id~ : “$by\~user~”, num\~tutorial~ : {$max : “$likes”}}}]) $push 在结果文档中插入值到一个数组中。 db.mycol.aggregate([{$group : {\~id~ : “$by\~user~”, url : {$push: “$url”}}}]) $addToSet 在结果文档中插入值到一个数组中,但不创建副本。 db.mycol.aggregate([{$group : {\~id~ : “$by\~user~”, url : {$addToSet : “$url”}}}]) $first 根据资源文档的排序获取第一个文档数据。 db.mycol.aggregate([{$group : {\~id~ : “$by\~user~”, first\~url~ : {$first : “$url”}}}]) $last 根据资源文档的排序获取最后一个文档数据 db.mycol.aggregate([{$group : {\~id~ : “$by\~user~”, last\~url~ : {$last : “$url”}}}]) -
其他非求和方法
-
投影?
1
2
3
4
5
6db.article.aggregate(
{ $project : {
title : 1 ,
author : 1 ,
}}
);这样结果中就只有\~id~,tilte和author三个字段(默认情况下\~id字段是被包含~)
如果要想不包含\~id需要显式指定~:1
2
3
4
5
6db.article.aggregate(
{ $project : {
_id : 0 ,
title : 1 ,
author : 1
}}); -
匹配
match获取了分数在70至90之间的文档,
然后将结果通过管道送给下一个group语句处理1
2
3
4db.articles.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] );所以语句中最外层的
[]
就是为了多条语句的管道操作准备的
不过该[]
不必须 -
跳过
1
db.article.aggregate({ $skip : 5 });
-
-
-
正则表达式
-
支持情况
支持PCRE(Perl Compatible Regular Expression)
-
基本用法
1
{$regex:"runoob"}
或者简写为
1
/runoob/
-
选项的使用
1
{$regex:"runoob",$options:"$i"}
或者简写为
1
/runoob/i
-
注意
-
索引比正则表达式快
-
正则中使用变量需要使用eval
1
eval("/" + value + "/i")
-
-
索引
储存索引至RAM,加快查询速度
-
创建索引
用法
1
db.collection.createIndex(keys, options)
参数有
Parameter Type Description background Boolean 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 “background” 可选参数。 “background” 默认值为*false*。 unique Boolean 建立的索引是否唯一。指定为true创建唯一索引。默认值为*false*. name string 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 dropDups Boolean 3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 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. 举例
同样使用1表示升序,-1表示降序1
db.values.createIndex({open: 1, close: 1}, {background: true})
数据库其他操作
复制
为了保障数据的安全性,将数据复制到另一个服务器上
主节点操作并纪录log,从节点定期读取log并采取同样的操作以保证数据一致
在设计上保证每个节点都可以是主节点,可以自动故障转移
从节点又称为副本集 replica set
举例:在27017端口创建一个名为rs0的副本集,数据存放在D盘某位置
1 | mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0 |
还可以给副本集添加成员:rs.add(HOST~NAME~:PORT)
例如 rs.add(“mongod1.net:27017”)
不过只有主节点可以添加,判断是否为主节点可以使用 db.isMaster()
分片
请求数量大时,将对一个服务器的请求分散到多个服务器上以减轻压力
或者数据过多,一个服务器存储不下
MongoDB的分片集群结构中有三个角色
- Router 前端粮油,使整个集群看起来像一个
- Config Server 存储其他信息?
- Shard(replica set) 实际存储数据
-
举例
-
服务器设计如下
Shard Server 1:27020
Shard Server 2:27021
Shard Server 3:27022
Shard Server 4:27023
Config Server :27100
Route Process:40000 -
分别启动服务器
1
2
3
4
5
6
7
8
9shared server
mongod --port 27020 --dbpath=/www/mongoDB/shard/s0 --logpath=/www/mongoDB/shard/log/s0.log --logappend --fork
mongod --port 27021 --dbpath=/www/mongoDB/shard/s1 --logpath=/www/mongoDB/shard/log/s1.log --logappend --fork
mongod --port 27022 --dbpath=/www/mongoDB/shard/s2 --logpath=/www/mongoDB/shard/log/s2.log --logappend --fork
mongod --port 27023 --dbpath=/www/mongoDB/shard/s3 --logpath=/www/mongoDB/shard/log/s3.log --logappend --fork
config server
mongod --port 27100 --dbpath=/www/mongoDB/shard/config --logpath=/www/mongoDB/shard/log/config.log --logappend --fork
route process
mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500其中chunkSize单位为MB,默认200MB
-
配置sharding
1
2
3
4
5
6
7
8# 登录
mongo admin --port 40000
# 添加节点
db.runCommand({ addshard:"localhost:27020" })
# 设置被分片的数据库
db.runCommand({ enablesharding:"test" })
# 什么配置?
db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}}) -
使用
正常使用40000接口的数据库即可
-
备份与恢复
数据导出到指定目录或从目录导入数据库的操作
-
备份
1
mongodump -h dbhost -d dbname -o dbdirectory
- host可以带端口号,如127.0.0.1:27017
- 也可以使用port选项指定端口
- 不指定dbnmae会默认备份所有DB
- 若指定dbname,会在指定路径下自动创建一个同被备份数据库同名的文件夹
- collection选项可以指定集合名
-
恢复
1
mongorestore -h <hostname><:port> -d dbname <path>
- –host <:port>, -h <:port>
MongoDB所在服务器地址,默认为: localhost:27017 - –db, -d
需要恢复的数据库实例,例如:test,当然这个名称也可以和备份时候的不一样,比如test2 - –drop
恢复的时候,先删除当前数据,然后恢复备份的数据。备份后添加修改的数据都会被删除 - –dir
指定备份的目录 - <path>
mongorestore最后的一个参数,设置备份数据所在位置,例如
c:\data\dump\test,需要指定数据库名对应的文件夹
不能同时指定 <path> 和 --dir 选项,–dir也可以设置备份目录。
- –host <:port>, -h <:port>
监控
用于了解性能
- mongostat 看各种stat
- mongotop 看那些查询花大量的时间
数据库高级操作
关系
指多个文档在逻辑上的关系
可以有几种关系
- 1:1
- 1:N
- N:1
- N:N
有两种方法建立关系
- 嵌入
- 引用
比如用户Tom Hanks住在Los Angeles
分别有不关联的信息:
用户集合
1 | { |
地址集合
1 | { |
-
嵌入
直接手动/程序写入到数据中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18"_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"
}]
}使用简单
1
db.users.findOne({"name":"Tom Benzamin"},{"address":1})
-
引用
-
手动引用
通过ObjectId来引用
1
2
3
4
5
6
7
8
9
10{
"_id":ObjectId("52ffc33cd85242f436000001"),
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin",
"address_ids": [
ObjectId("52ffc4a5d85242602e000000"),
ObjectId("52ffc4a5d85242602e000001")
]
}使用时为了获取信息需要查询两次
1
2var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})
var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})其中第二句手动指定了要查询的集合address
-
DBRefs
一个文档从多个集合引用文档时使用
用起来像是外键,1
2
3
4
5
6
7
8
9
10{
"_id":ObjectId("53402597d852426020000002"),
"address": {
"$ref": "address_home", // 集合名称
"$id": ObjectId("534009e4d852427820000002"), // id
"$db": "runoob"}, // db名称
"contact": "987654321",
"dob": "01-01-1991",
"name": "Tom Benzamin"
}数据库本身仍然没有任何联系,
只是方便了程序调用1
2
3var user = db.users.findOne({"name":"Tom Benzamin"})
var dbRef = user.address
db[dbRef.$ref].findOne({"_id":(dbRef.$id)}) // 注意这里使用了db[collectionName]的形式指定使用的集合
-
覆盖索引查询
若查询条件是索引,并且结果在同一个索引中?
借助在RAM中的索引,
可以使用覆盖索引查询大大地加快查询的速度.
举例
若一个集合大致结构如下
1 | { |
且此集合已经添加了索引
1 | db.users.ensureIndex({gender:1,user_name:1}) |
使用以下查询时可以很快
这里指定了以user~name排序~,且不要输出id
1 | db.users.find({gender:"M"},{user_name:1,_id:0}) |
若使用以下查询,由于id没有指定时为默认输出,而id又不是索引的一部分
查询会慢
1 | db.users.find({gender:"M"},{user_name:1}) |
查询分析
用于分析索引的设置是否得当
-
explain()
提供了索引及查询统计
用法: db.collectionName.find({something}).explain()
输出一些信息 -
hint()
在检索时强制使用某些索引1
db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})
原子操作
MongoDB不支持事务,也不要求数据有完整性,但还是提供了原子操作
保存,修改,删除等,都是.
为了保证关联的集合也是同步更新的,通常加入其他字段用于程序判断
原子操作重用的指令有
- $set
- $unset
- $int
- $push
- $pushAll
- $pull
- $addToSet
- $pop
- $rename
- $bit
高级索引
-
数组作为索引
为数组建立索引时,会自动将数组中的每个元素都建立索引
查询时可以变快
数据:1
2
3
4
5
6
7
8
9
10
11
12
13{
"address": {
"city": "Los Angeles",
"state": "California",
"pincode": "123"
},
"tags": [
"music",
"cricket",
"blogs"
],
"name": "Tom Benzamin"
}建立索引
1
db.users.ensureIndex({"tags":1})
查询
1
db.users.find({tags:"cricket"})
验证
1
db.users.find({tags:"cricket"}).explain()
结果中显示 “cursor” : “BtreeCursor tags~1~” ,则表示已经使用了索引
-
子文档作为索引
上例中若想将address这个子文档作为索引,需要对每个子文档的元素都建立索引
这里使用了点的写法,表示索引属于子文档1
db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1})
检索数据时也使用点的写法
不必关注检索时使用关键词的顺序1
db.users.find({"address.state":"California","address.city":"Los Angeles"})
-
全文检索
存储对象是文章时,会为文章中每个词都建立索引,记录词的位置和次数.
支持英语在内的部分表声文字
默认开启全文检索功能.
可以将保存文章的字段作为索引
比如有数据1
2
3
4
5
6
7{
"post_text": "enjoy the mongodb articles on Runoob",
"tags": [
"mongodb",
"runoob"
]
}可以这样建立索引
1
db.posts.ensureIndex({post_text:"text"})
使用时,似乎不必指明需要查询哪个索引,但这里使用了$text和$search,功能不明
1
db.posts.find({$text:{$search:"runoob"}})
删除索引:
1
2
3
4# 查询
db.<collectionName>.getIndexs
# 删除
db.<collectionName>.dropIndex("xxxxxxxx")
索引限制
- 索引占空间,读取操作不多时不要使用索引
- 索引不能被一些操作符相关的操作使用
- 非操作符 $nin,$not
- 算术 $mod
- $where子句
- 字段占空间太大将不会被创建索引
- 索引不能超过64个
- 名称长度不能超过128字符
- 符合索引最多31个字段
ObjectId
4时间戳+3机器标识码+2PID+3随机数
共12字节
不使用常规主键,原因是在多个服务器上同步增加主键费时费力
Map Reduce
将大批量的数据分解执行(MAP),然后将结果合并成最终结果(REDUCE).
用法
1 | db.collection.mapReduce( |
举例
插入同样意义的数据,其中active5条(其中数据mark的4条,数据runoob的1条),disable3条
1 | db.posts.insert({ |
命令中要求按照user~name分别统计active的数量~
1 | db.posts.mapReduce( |
结果
1 | { |
post~total的内容~
1 | { "_id" : "mark", "value" : 4 } |
GridFS
-
介绍
用于存储超过16M(BSON文件限制)的文件
将大文件分割成小块chunk,一般256k一个,所有的chunk被作为文档保存在chunks集合中
除此之外还将文件有关的metadate放在file集合中
比如
files集合中的文档1
2
3
4
5
6
7
8{
"_id": ObjectId("534a75d19f54bfec8a2fe44b"),
"filename": "test.txt",
"chunkSize": NumberInt(261120),
"uploadDate": ISODate("2014-04-13T11:32:33.557Z"),
"md5": "7b762939321e146569b07f72c62cca4f",
"length": NumberInt(646)
}chunks集合中的一个文档
注意id是对应的1
2
3
4
5{
"files_id": ObjectId("534a75d19f54bfec8a2fe44b"),
"n": NumberInt(0),
"data": "Mongo Binary Data"
} -
添加文件
1
mongofiles -d gridfs put song.mp3
gridfs是一个命令集,put是其命令
-
查看添加的文件
默认放在了fs(集合的集合,理论上可以有无限个集合嵌套)下,
1
db.fs.files.find({filename:"song.mp3"})
得到
1
2
3
4
5
6
7{
_id: ObjectId('534a811bf8b4aa4d33fdf94d'),
filename: "song.mp3",
chunkSize: 261120,
uploadDate: new Date(1397391643474), md5: "e4f53379c909f7bed2e9d631e15c1c41",
length: 10401959
}然后到chunks中查找相同的fileid
1
db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})
固定集合
-
创建
指定了size和最大的文档数
1
db.createCollection("cappedLogCollection",{capped:true,size:10000,max:1000})
-
判断
1
db.cappedLogCollection.isCapped()
-
转换已存在的集合至固定集合
1
db.runCommand({"convertToCapped":"posts",size:10000})
-
查询时注意
返回的顺序要么是插入顺序,要么是反向
1
db.cappedLogCollection.find().sort({$natural:-1})
-
其他特点
- 可以插入和更新,但不允许超出size,否则失败
- 不允许删除一条记录,但可以删除整个集合
自动增长
- ~id允许自定义值~
- 需自行在程序中建立增加的代码,并且在DB中加入一个用于记录自增id的集合
举例
-
用于计数的复制集合例
其~id的命名是为了方便地找到counters的位置~,
sequence~value就是真正记录自增id的字段~1
2
3
4{
"_id":"productid",
"sequence_value": 0
} -
程序中的自增代码
带有查找并更新的功能
1
2
3
4
5
6
7
8
9function getNextSequenceValue(sequenceName){
var sequenceDocument = db.counters.findAndModify(
{
query:{_id: sequenceName },
update: {$inc:{sequence_value:1}},
"new":true
});
return sequenceDocument.sequence_value;
} -
正常使用的过程
1
2
3
4
5
6
7
8
9db.products.insert({
"_id":getNextSequenceValue("productid"),
"product_name":"Apple iPhone",
"category":"mobiles"})
db.products.insert({
"_id":getNextSequenceValue("productid"),
"product_name":"Samsung S3",
"category":"mobiles"})结果如下
1
2
3{ "_id" : 1, "product_name" : "Apple iPhone", "category" : "mobiles"}
{ "_id" : 2, "product_name" : "Samsung S3", "category" : "mobiles" }
与其他程序的API
略
java
PHP
PHP7
Node.js
管理工具
监控工具
- Munin 插件
- Gangila 插件
- Cacti 插件
GUI工具
- Fang of Mongo 网页格式
- Futon4Mongo
- Mongo3 Ruby写成
- MongoHub OSX平台
- Opricot 基于浏览器,由PHP写成
- Database Master window平台
- RockMongo PHP5写成