MongoDB 是一个基于分布式文件存储,介于关系和非关系之间、高性能、高可用、自动扩展 的文档数据库。
特性
- 不提供事务,但提供许多原子操作
- 分布式架构,亿级数据量级支持
- BSON文档结构匹配编程语言的原生数据类型
- 通过嵌入文档避免了极耗资源的
JOIN
操作(但也支持引用关系)
安装
# 新增mongo源 /etc/yum.repos.d/mongodb-org-3.4.repo
[mongodb-org-3.4]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
# yum安装
sudo yum install -y mongodb-org
# 服务启动
sudo service mongod start
sudo chkconfig mongod on
# 配置文件
- 配置文件 `/etc/mongod.conf`
- 默认数据目录 `/var/lib/mongo`
- 默认日志目录 `/var/log/mongodb`
Mysql概念对比
Mysql : Mongodb
关系对比
- 数据库 : 数据库 (
mongodb
预留三个库admin、local、config
) - 表 : 集合
collection
- 行 : 文档
document
- 列 : 域
field
(mongodb
每个文档的域结构不要求相同) - id :
_id
(必选且默认是ObjectId
类型的,自动生成非自增)
CURD语法
连接 mongo [ip[:27017]/]库
## 基础操作 ##
mongodb://账号:密码@地址/[库] #切换服务连接
show dbs
use dbName #切换库,不存在则新建库(库里必须有数据才会罗列出来)
db #显示当前库
show collections #罗列集合
db.集合.drop() #删除集合
db.dropDatabase() #删除当前库
## 插入文档 ##
db.集合.insert({文档}) #集合不存在则新建
## 更新文档文档 ##
#1. update字段更新
db.集合.update(
{json过滤},
{
$set: {字段:值},
$inc: {字段:增量}
},
{ #3个可选项及默认值
upsert: false, #文档不存在是否插入
multi: false, #是否更新全部匹配文档
writeConcern: <document> #抛出异常级别
}
)
#2. save文档覆盖更新
db.集合.save({json新文档}) #_id查找文档
## 删除文档文档 ##
db.集合.remove(
{json过滤},
{
justOne: false, #是否只删除一个匹配文档
writeConcern: <document>
}
)
db.集合.remove({}) #删除所有文档
## 查询文档 ##
db.集合.find|findOne(
{json过滤},
{字段1:1, 字段2:0} #可选,指定字段是否显示
).sort({字段1:1, 字段2:0}).limit(3).skip(3)pretty() #常规查询
查询操作符
- 条件操作符:`$eq、$lte、$gte、...`
- 逻辑操作符:`$or、$and、$not、$nor`
- 元素操作符:`$exists、$type(常用类型:2string、3object、4array、8bool、9date、10null)`
- 计算操作符:`$regex、$text(文本搜索)、$mod、$where`
- GEO操作符:`$geoWithin、$geoIntersects、$near、$nearSphere`
JSON过滤查询
# 默认语句间AND关系
{
key1: value1,
key2: {
查询操作符: value2
}
}
# 过滤语句合并(逻辑操作符支持:$or、$and、$not、$nor)
{
$逻辑操作符: [
{key1: value1},
{key2: value2}
]
}
聚合之 单一目标
## 统计 ##
db.集合.find({json过滤}).count();
db.集合.count({json过滤});
## 去重查询 ##
- 函数式:db.集合.distinct(字段名, {json过滤})
- 原语式: db.runCommand({
distinct: 集合,
key: 字段名,
query: {json过滤},
});
聚合之 管道
# 聚合查询
db.集合.aggregate([
{#geoNear管道表达式(若存在,则为了使用地理空间信息索引必须作为第一个管道)
$geoNear: {
near: [经度,纬度],
distanceField: 自定义距离结果字段名,
maxDistance: 最大距离,
query: {json过滤},
includeLocs: 指定文档中的位置字段名,
num: 指定返回结果数,
}
},
{#match管道表达式 (为了降低管道处理的文档量级,过滤操作要尽量前置)
$match: {json过滤},
},
{#group管道表达式 分组文档进行聚合计算
$group: {
_id: {field1:"$field1", field2:"$field2"}或"$字段名",
自定义结果名: {
$聚合方法: $字段名 #可选聚合方法 $sum、$avg、$min、$max、$first、$last
}
}
},
{#project管道表达式 投影操作(只输出需要的字段)
$project: {字段1:1, 字段2:0}
},
{#skip管道表达式
$skip: 5
},
{#limit管道表达式
$limit: 100
},
{#sort管道表达式
$sort: {字段1:1, 字段2:0}
},
。。。
]);
聚合之 MapReduce
可用来构建 大型的、复杂的 聚合处理
db.collection.mapReduce(
# map函数 - 映射分组文档值
function(){
# js逻辑
this;
key = xxx;
value = yyy;
emit(key, value);
},
# reduce函数 - 归一文档值集合得到结果
function(key, values) {
# js逻辑
result = dosomething(values);
return result;
},
# 可选项
{
out: 指定结果存放集合名,
query: map操作前的过滤,
sort: map操作前的排序,
limit: map操作前的限量,
}
).find() #find直接显示结果,没有find则显示处理状态分析
索引管理
创建索引
- 每个字段索引要单独建立
- 创建索引时指定多个字段则为复合索引(顺序重要)
- 子文档索引用点号连接
parentField.childField:1
- 索引存储在内存,若超出则自动删除一部分
# 创建
db.集合.ensureIndex(
{字段1:1, 字段2:-1, ...}, #指定了升降序的复合索引
{# 可选参数及其默认值
background: false, #后台创建
unique: false, #唯一索引
name: 'my_index', #索引名称
}
)
# 罗列索引
db.集合.getIndexes()
# 删除
db.集合.dropIndex(索引名)
强制使用索引
db.集合.find().hint({字段1:1, 字段2:-1, ...})
覆盖索引查询
覆盖索引的查询直接从内存索引中查询,而不会扫描数据库。
需满足:
- 所有过滤字段是索引的
- 所有结果字段在同一索引中(结果字段需投影剔除_id字段)
全文检索
- 倒排索引结构
- 每个集合只能有一个全文索引,但索引可以覆盖多个字段
- 使用空格、标点符号作为停词来进行分词(3.2企业版支持中文)
# 创建索引
db.集合.ensureIndex({字段名1:"text", ...})
# 全文索引上检索
db.集合.find({$text:{$search:"关键词"}})
查询分析
查询语句后面追加 .explain()
# 重要指标
- indexOnly 是否为覆盖索引查询
- cursor 索引查询是BtreeCursor,常规查询是BasicCursor
- indexBounds 具体使用的索引
- n 返回文档数
- nscanned/nscannedObjects 扫描文档数
- millis 查询耗时
数据库命令
Database Commands
是除了CURD
之外的mongodb
操作,所有非CURD
操作都有此入口
db.runCommand({
})
维护命令
mongodump -h host -d dbname -c collectionname -o dbdirectory #备份
mongorestore -h host -d dbname -c collectionname bakpath #恢复
mongostat #状态资源监测
mongotop #集合层次的读写时间监测
数据建模
MongoDB
支持两种关系模型
- 嵌入关系 - 查询方便,但数据量级容易庞大
- 引用关系 - 查询多次,但数据量级较小
* `DBRefs` - 支持跨库跨集合引用 `引用字段名: {$ref:集合名, $id:引用id, $db:可选库名}`
* 手动引用 `引用字段名:引用id`
GridFS
- 用于集合的大文件存储(因为Bson文档不支持16M)
- 涉及两个集合
fs.files、fs.chunks
固定集合
# 特点
- 大小固定
- 性能出色,插入及查询极快
# 场景
- 日志存储
- 少量文档缓存
PHP5 Mongo驱动
$con = new MongoClient('mongodb://rs1.example.com,rs2.example.com', ['replicaSet' => 'rs']);
$db = $con->myDB; #MongoDB类
$collection = $db->myCollection; #MongoCollection类
## 集合CURD ##
$collection->insert(array $obj);
$collection->update(array $criteria, array $newObj);
$collection->update(array $criteria, ['$set' => array $newData]);
$collection->remove(array $criteria);
$cursor = $collection->find(array $criteria); #MongoCursor类
foreach($cursor as $doc){...}
## 集合:单一聚合 ##
$collection->count(array $criteria); #统计
$collection->distinct($fieldName, array $criteria); #去重查询
## 集合:聚合管道 ##
$collection->aggregate([
array(
'$match' => array $criteria,
),
array(
'$group' => [
'_id' => array('key1_field' => '$key1_field', ...),
'resultFieldName' => ['$聚合方法' => '$fieldName'],
],
),
]);