MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。关于它要想了解更多,请参阅《三分钟了解mongodb》
目录
1.NOSQL分类
2.特点
3.数据模型
4.演示数据
5.基本概念
5.1 ACID VS BASE
5.2 SQL到Mongo映射
5.3文档
5.4 集合
5.5 固定集合
5.6 数据库
5.7 元数据
5.8 管道
5.9 数据类型
6. mongo维护
6.1 安装
6.2 启动/关闭
6.3 导入/导出
6.4 备份/恢复
6.5 数据修复/Fsnc锁
6.6 用户管理
6.7 常见命令
7. 数据库操作
7.1 服务端脚本
7.2 新建
7.3 删除
7.4 runCommand
7.5 findAndModify
8. 文档操作
8.1 文档插入
8.1.1 插入
8.1.2 批量插入
8.1.3 save
8.2 文档删除
8.3 文档更新
8.4 固定集合
8.5 数据模型校验器
9. 数据检索
10. 索引
10.1 索引详解
10.1.1 Hint
10.1.2 Explain
10.2 联合索引
10.3 索引数组
10.4 空间索引
11. Map-Reduce
12. GridFS
13.1 复制
13.1.1 主从复制
13.1.2 副本集
13.2 分片
14 管理工具
14.1 MongoVUE
14.2 RockMongo
14.3 Robo 3T
15. java-driver
具体参考《一览NoSQL各种分类 》
MongoDB特征 |
|
核心优势 |
灵活文档模型、高可用复制集、可拓展分片集群 |
功能特点 |
二级索引、地理位置索引、全文索引、aggregate、map-reduce、GridFs |
不足之处 |
不支持事务、不支持表链接 |
一个MongoDB 实例可以包含一组数据库,一个DataBase 可以包含一组Collection(集合),一个集合可以包含一组Document(文档)。一个Document包含一组field(字段),每一个字段都是一个key/value pair。
key: 必须为字符串类型。
value:可以包含如下类型。
var persons =[{
name: "tom",
age: 25,
email: "[email protected]",
c: 75,
m: 66,
e: 97,
country: "USA",
books: ["PHP", "JAVA", "EXTJS", "C++"]
}, {
name: "lili",
age: 26,
email: "[email protected]",
c: 75,
m: 63,
e: 97,
country: "USA",
books: ["JS", "JAVA", "C#", "MONGODB"]
}, {
name: "zhangsan",
age: 27,
email: "[email protected]",
c: 89,
m: 86,
e: 67,
country: "China",
books: ["JS", "JAVA", "EXTJS", "MONGODB"]
}, {
name: "lisi",
age: 26,
email: "[email protected]",
c: 53,
m: 96,
e: 83,
country: "China",
books: ["JS", "C#", "PHP", "MONGODB"]
}, {
name: "zhaoliu",
age: 27,
email: "[email protected]",
c: 99,
m: 96,
e: 97,
country: "China",
books: ["JS", "JAVA", "EXTJS", "PHP"]
}, {
name: "lizhenxian",
age: 27,
email: "[email protected]",
c: 35,
m: 56,
e: 47,
country: "Korea",
books: ["JS", "JAVA", "EXTJS", "MONGODB"]
}, {
name: "lixiaoli",
age: 21,
email: "[email protected]",
c: 36,
m: 86,
e: 32,
country: "Korea",
books: ["JS", "JAVA", "PHP", "MONGODB"]
}, {
name: "zhangsuying",
age: 22,
email: "[email protected]",
c: 45,
m: 63,
e: 77,
country: "Korea",
books: ["JS", "JAVA", "C#", "MONGODB"]
}, {
name: "liuxiang",
age: 31,
email: "[email protected]",
c: 99,
m: 96,
e: 97,
country: "China",
books: ["JS", "JAVA", "EXTJS", "VS"],
address: {
city: "上海",
area: "普陀区XX路"
}
}, {
name: "chenlong",
age: 55,
email: "[email protected]",
c: 99,
m: 96,
e: 97,
country: "China",
books: ["JAVA", "EXTJS", "VS"],
address: {
city: "香港",
area: "中环XX路"
}
}
]
for(var i = 0;i
在计算机科学中, CAP定理(CAP theorem), 又被称作 布鲁尔定理(Brewer's theorem), 它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。
因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:
BASE:Basically Available, Soft-state, Eventually Consistent。由 Eric Brewer 定义。BASE是NoSQL数据库通常对可用性及一致性的弱要求原则:
ACID |
BASE |
原子性(Atomicity) |
基本可用(Basically Available) |
一致性(Consistency) |
软状态/柔性事务(Soft state) |
隔离性(Isolation) |
最终一致性 (Eventual consistency) |
持久性 (Durable) |
|
SQL术语/概念 |
MongoDB术语/概念 |
解释/说明 |
database |
database |
数据库 |
table |
collection |
数据库表/集合 |
row |
document |
数据记录行/文档 |
column |
field |
数据字段/域 |
index |
index |
索引 |
table joins |
|
表连接,MongoDB不支持(内嵌文档和链接) |
primary key |
primary key |
主键,MongoDB自动将_id字段设置为主键 |
aggregation |
|
Mongodb内置大量聚合管道 |
文档是 MongoDB 中数据的基本单位,类似于关系数据库中的行(但是比行复杂)
注意:
文档键命名规范:
集合就是一组文档,类似于关系数据库中的表。集合是无模式的,集合中的文档可以是各式各样的。
注意:
Capped collections 就是固定大小的collection。它有很高的性能以及队列过期的特性,collection的数据存储空间值提前分配的。
db.createCollection("mycoll", {capped:true, size:100000})
db.cappedLogCollection.isCapped() --是否为固定集合
适用场景:
一个MongoDB 实例可以承载多个数据库。它们之间可以看作相互独立,每个数据库都有独立的权限控制。在磁盘上,不同的数据库存放在不同的文件中。MongoDB 中存在以下系统数据库。
数据库名可以是满足以下条件的任意UTF-8字符串:
数据库的信息是存储在集合中。它们使用了系统的命名空间:已废弃
|
|
|
|
|
|
|
|
|
|
|
|
对于修改系统集合有如下限制。
管道在Linux中一般用于将当前命令的输出结果作为下一个命令的参数。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 |
正则表达式类型。用于存储正则表达式。 |
数据库服务和客户端 |
|
mongod |
类似mysqld |
mongo |
类似mysql/sqlplus 其实是个javascript引擎 |
mongoexport |
导出命令 |
mongoimport |
导入命令 |
mongotop |
监控工具,跟踪数据库执行每个集合读写操作耗时 |
mongostat |
监控工具,类似linux vmstat |
mongos |
路由工具(分片) |
mongodump |
数据备份 |
mongorestore |
数据恢复 |
mongofiles |
GridFS(添加文件) |
mongoperf |
独立检查mongoDB的I/O性能的工具,类似linux iostat |
mongooplog |
用于从运行的mongod服务中拷贝运行日志到指定的服务器,主要用于增量备份 |
bsondump |
用于将导出的BSON文件格式转换为JSON格式 |
mongosniff |
(linux及unix有此工具)用于监控连接到mongodb的TCP/IP连接,类似于tcpdump |
启动服务端:
参数 |
描述 |
--help |
帮助 |
--bind_ip |
绑定服务IP,若绑定127.0.0.1,则只能本机访问,不指定默认本地所有IP |
--logpath |
定MongoDB日志文件,注意是指定文件不是目录 |
--logappend |
使用追加的方式写日志 |
--dbpath |
指定数据库路径 |
--port |
指定服务端口号,默认端口27017 |
--serviceName |
指定服务名称 |
--serviceDisplayName |
指定服务名称,有多个mongodb服务时执行。 |
--install |
指定作为一个Windows服务安装。 |
--auth |
用安全认证方式启动 |
停止服务端:
启动客户端:
#window shell
Cd C:\
mkdir mongodbdata
mongod -dbpath C:\mongodbdata
mongo --help
mongo localhost:27017
show dbs
exit
mongo 127.0.0.1:27017/admin #admin身份进入
利用config配置文件来启动数据库改变端口为8888
mongodb.conf文件:
dbpath = D:\sortware\mongod\db
port = 8888
启动:
mongod.exe --config ../mongodb.conf
1.导出数据(中断其他操作)
-d 指明使用的库
-c 指明要导出的表
-o 指明要导出的文件名
-csv 制定导出的csv格式
-q 过滤导出
--type
mongoexport -d foobar -c persons -o D:/persons.json
mongoexport --host 192.168.0.16 --port 37017
2.导入数据(中断其他操作)
mongoimport --db foobar --collection persons --file d:/persons.json
1.运行时备份mongodump
mongodump --host 127.0.0.1:27017 -d foobar -o d:/foobar
2.运行时恢复mongorestore
db.dropDatabase() --删除原本的数据库
mongorestore --host 127.0.0.1:27017 -d foobar -directoryperdb d:/foobar/foobar
3.懒人备份
mongoDB是文件数据库这其实就可以用拷贝文件的方式进行备份
1.Fsync的使用
2.上锁和解锁
db.runCommand({fsync:1,lock:1}) --上锁
db.currentOp() --解锁
3.数据修复
当停电等不可逆转灾难来临的时候,由于mongodb的存储结构导致会产生垃圾数据,在数据恢复以后这垃圾数据依然存在,这是数据库提供一个自我修复的能力.使用起来很简单
db.repairDatabase()
#shell
mongo localhost:27017/admin
show roles
use test
db.createUser({
user: "alex",
pwd: "123",
roles: [ { role: "__system", db: "admin" } ]
}
)
mongod -dbpath C:\mongodbdata --rest –auth --cmd
db.auth("alex","123")
db.dropUser(“alex”)
db.runCommand({usersInfo:1}) #all users
db.system.users.find().pretty() #use admin
#远程连接
mongo 192.168.2.203:27017/gesb -ureaduser -pJcizexRo4
1.Eval
db.eval("function(name){ return name}","uspcat")
2.Javascript的存储(服务上保存js变量活着函数共全局调用)
db.system.js.insert({_id:name,value:”uspcat”}) --加载到特殊集合system.js
db.eval("return name;")
System.js相当于Oracle中的存储过程,因为value不单单可以写变量还可以写函数体也就是javascript代码
use test #新建test db(若不执行insert,数据库不会被创建)
db.person.insert({name:"mongodb"})
db.person.find()
db
show dbs
use test
db.dropDatabase()
show dbs
runCommand可以执行mongoDB中的特殊函数,
#用命令执行完成一次删除表的操作
db.runCommand({drop:"map"})
{
"nIndexesWas" : 2,
"msg" : "indexes dropped for collection",
"ns" : "foobar.map",
"ok" : 1
}
# 查询服务器版本号和主机操作系统
db.runCommand({buildInfo:1})
#查询执行集合的详细信息,大小,空间,索引等……
db.runCommand({collStats:"persons"})
#查看操作本集合最后一次错误信息
db.runCommand({getLastError:"persons"})
findAndModify就是特殊函数之一他的用于是返回update或remove后的文档
runCommand({“findAndModify”:”processes”,
query:{查询器},
sort{排序},
new:true
update:{更新器},
remove:true
).value
ps = db.runCommand({
"findAndModify":"persons",
"query":{"name":"text"},
"update":{"$set":{"email":"1221"}},
"new":true
}).value
do_something(ps)
show tables
db.[documentName].insert(document)
shell 这样执行是错误的 db.[documentName].insert([{},{},{},……..]),shell 不支持批量插入
想完成批量插入可以用mongo的应用驱动或是shell的for循环
> function batch(){
... for(var i=0;i<5;i++){
... db.persons.insert({name:"person"+i})
... }}
> batch()
save操作和insert操作区别在于当遇到_id相同的情况下,save完成保存操作, insert则会报错
db.[documentName].remove(
,
{
justOne: ,
writeConcern:
}
)
小技巧:
db.[documentName].update(
,
,
{
upsert: ,
multi: ,
writeConcern:
}
)
$addToSet与$each结合完成批量数组更新
db.text.update({_id:1000},{$addToSet:{books:{$each:[“JS”,”DB”]}}})
注意:存在分配与查询效率
当document被创建的时候DB为其分配没存和预留内存当修改操作,不超过预留内层的时候则速度非常快反而超过了就要分配新的内存则会消耗时间
db.persons.update({name:"person1"},{$set:{name:"pp"}})
db.[documentName].update({查询器},{修改器},true)
db.[documentName].update({查询器},{修改器},false, true)
db.createCollection("mycoll",{size:100,capped:true,max:10})
db.runCommand({convertToCapped:”persons”,size:100000})
db.mycoll.find().sort({$natural:-1})
这是个特殊的只能用到固定级和身上的游标,他在没有结果的时候,也不回自动销毁他是一直等待结果的到来
文档格式太灵活也会有问题的,不便于维护
db.createCollection( "contacts",
{
validator: { $or:
[
{ phone: { $type: "string" } },
{ email: { $regex: /@mongodb\.com$/ } },
{ status: { $in: [ "Unknown", "Incomplete" ] } }
],
validationAction: "warn"
}
}
)
db.contacts.insert( { name: "Amanda", status: "Updated" } )
//添加一个验证器
db.runCommand( {
collMod: "contacts",
validator: { $or: [ { phone: { $exists: true } }, { email: { $exists: true } } ] },
validationLevel: "moderate"
} )
参考我另一篇《数据检索》
for(var i = 0 ; i<20000 ;i++){
db.books.insert({number:i,name:i+"book"})
}
db.books.ensureIndex({number:1})
db.books.ensureIndex({name:-1},{name:”bookname”}) //指定索引名称
db.books.ensureIndex({name:-1},{unique:true})
db.books.ensureIndex({name:-1},{unique:true,dropDups:true}) //踢出重复值
db.books.ensureIndex({name:-1},{background:true})
db.system.indexes.find() //已废弃
db.persons.getIndexes()
db.persons.reIndex()
db.persons.dropIndex(“bookname”)
db.persons.dropIndexes()
注意:
索引限制:
索引不能被以下的查询使用:
所以,检测你的语句是否使用索引是一个好的习惯,可以用explain来查看。
最大范围
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.books.find({name:"1book",number:1}).hint({name:-1})
db.books.find({name:"1book"}).explain()
更多
更多
mongoDB提供强大的空间索引可以查询出一定范围的地理坐标.看例子
//添加2D索引,默认会建立一个[-180,180]之间的2D索引
db.map.ensureIndex({"gis":"2d"},{min:-1,max:201})
//测试数据
var map=[{"gis":{"x":185,"y":150}},{"gis":{"x":70,"y":180}},{"gis":{"x":75,"y":180}},{"gis":{"x":185,"y":185}},{"gis":{"x":65,"y":185}},{"gis":{"x":50,"y":50}},{"gis":{"x":50,"y":50}},{"gis":{"x":60,"y":55}},{"gis":{"x":65,"y":80}},{"gis":{"x":55,"y":80}},{"gis":{"x":0,"y":0}},{"gis":{"x":0,"y":200}},{"gis":{"x":200,"y":0}},{"gis":{"x":200,"y":200}}]
for(var i = 0;i
Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。
db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
Map 函数必须调用 emit(key, value) 返回键值对。
参数说明:
GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。
GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档。
GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。
mongofiles.exe -d gridfs put c:\a.txt #cmd
mongofiles -d gridfs list #cmd
mongofiles -d gridfs delete "a.txt" #cmd
use gridfs
db.fs.files.find().pretty()
db.fs.chunks.find({files_id:ObjectId("583e8e25858ded1b343034cc")}).pretty()
13. 集群
mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。常见的搭配方式为:一主一从、一主多从,主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。
特征:
db.isMaster()
#8888.conf:
dbpath = D:\software\MongoDBDATA\07\8888 #主数据库地址
port = 8888 #主数据库端口号
bind_ip = 127.0.0.1 #主数据库所在服务器
master = true #确定我是主服务器
#7777.conf:
dbpath = D:\software\MongoDBDATA\07\7777 #从数据库地址
port = 7777 #从数据库端口号
bind_ip = 127.0.0.1 #从数据库所在服务器
source = 127.0.0.1:8888 #确定我数据库端口,这个配置项(source)可以用shell动态添加
slave = true #确定自己是从服务器
# 1.启动配置
mongod --config 7777.conf
mongod --config 8888.conf
# 客户端连接
mongo 127.0.0.1:7777
mongo 127.0.0.1:8888
2.主从复制的其他设置项
--only 从节点指定复制某个数据库,默认是复制全部数据库
--slavedelay 从节点设置主数据库同步数据的延迟(单位是秒)
--fastsync 从节点以主数据库的节点快照为节点启动从数据库
--autoresync 从节点如果不同步则从新同步数据库
--oplogSize 主节点设置oplog的大小(主节点操作记录存储到local的oplog中)
3.利用shell动态添加和删除从节点
不难看出从节点中关于主节点的信息全部存到local的sources的集合中
我们只要对集合进行操作就可以动态操作主从关系
挂接主节点:操作之前只留下从数据库服务
db.sources.insert({“host”:”127.0.0.1:8888”})
删除已经挂接的主节点:操作之前只留下从数据库服务
db.sources.remove({“host”:”127.0.0.1:8888”})
1.副本集概念
当A出现了故障,这时候集群根据权重算法推选出B为活跃的数据库,当A恢复后他自动又会变为备份数据库
#A.conf:
dbpath = D:\sortware\mongod\02\A
port = 1111 #端口
bind_ip = 127.0.0.1 #服务地址
replSet = child/127.0.0.1:2222 #设定同伴
#B.conf:
dbpath = D:\sortware\mongod\02\B
port = 2222
bind_ip = 127.0.0.1
replSet = child/127.0.0.1:3333
#C.conf:
dbpath = D:\sortware\mongod\02\C
port = 3333
bind_ip = 127.0.0.1
replSet = child/127.0.0.1:1111
2.初始化副本集
use admin
db.runCommand({"replSetInitiate":
{
"_id":'child',
"members":[{
"_id":1,
"host":"127.0.0.1:1111"
},{
"_id":2,
"host":"127.0.0.1:2222"
},{
"_id":3,
"host":"127.0.0.1:3333"
}]
}
})
3.查看副本集状态
rs.status()
4.节点和初始化高级参数
高级参数:Priority 0到1000之间 ,0代表是副本节点 ,1到1000是常规节点,arbiterOnly : true 仲裁节点
//用法,参考初始化副本集命令
members:[{
"_id":1,
"host":"127.0.0.1:1111“,
"arbiterOnly": true
}]
5.优先级相同时候仲裁组建的规则(B优先)
6.读写分离操作扩展读
7.Oplog
如果想故障恢复可以更彻底oplog可已经尽量设置大一些用来保存更多的操作信息
改变oplog大小
主库 --master --oplogSize size
1.插入负载技术
2.片键的概念和用处(利用key为片键进行自动分片)
3.什么时候用到分片呢?
4.分片步骤
db.runCommand({addshard:"127.0.0.1:8081",allowLocal:true})
db.runCommand({addshard:"127.0.0.1:8081",allowLocal:true})
db.runCommand({"enablesharding":"foobar"})
db.runCommand({"shardcollection":"foobar.bar","key":{"_id":1}})
5.查看配置库对于分片服务器的配置存储
db.printShardingStatus()
6.查看集群对bar的自动分片机制配置信息
mongos> db.shards.find()
{ "_id" : "shard0000", "host" : "127.0.0.1:8081" }
{ "_id" : "shard0001", "host" : "127.0.0.1:8082" }
7.保险起见的通常配置服务器做集群
8.分片与副本集一起使用
略
略
推荐
可参阅另一篇《jpa-mongo》
总结,如果想了解更多有关mongdb的常见问题,请参考见另一篇《mongodb常见疑问》