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, ...})

覆盖索引查询
覆盖索引的查询直接从内存索引中查询,而不会扫描数据库。
需满足:

  1. 所有过滤字段是索引的
  2. 所有结果字段在同一索引中(结果字段需投影剔除_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'],
		],
	),
]);