一、前言

1、 MongoDB是什么?

官网地址:https://www.mongodb.com/

MongoDB 是一个基于【分布式文件存储】的数据库,它属于NoSQL数据库。由 C++ 语言编写。旨在为 WEB 应用提
供【可扩展】的【高性能】数据存储解决方案。

MongoDB是一个介于非系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库
的。它支持的数据结构非常松散,是类似jsonbson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点
是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝
大部分功能,而且还支持对数据建立索引

NoSQL分类:键值型(key-value)、文档型(document) MongoDB就是文档型NoSQL数据库,它文档中的数据是以类似JSON的BSON格式进行存储的。我们拿JSON去理解,JSON中的 数据,都是key-value,key一般都是String类型的,而value就多种多样了。只有value的类型,后续有专门的讲解。记 住value中可以再存储一个文档。

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

mongodb不适合的场景 mongodb支持的类型_mongodb

2.MongoDB概念解析

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

MongoDB的默认数据库为"db",该数据库存储在data目录中(安装时,可以默认,可以指定,但是必须该目录是存在的)。

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

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

$ ./mongo MongoDB shell version: 3.0.6 connecting to: test > show 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 >

文档

文档是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点

{"site":"www.southiu.cn", "name":"南行"}

注意点

  1. 文档中的键/值对是有序的。
  2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  3. MongoDB区分类型和大小写。
  4. MongoDB的文档不能有重复的键。
  5. . 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:

  • 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
  • 以下划线"_"开头的键是保留的(不是严格要求的)。
  • .和$有特别的意义,只有在特定环境下才能使用。
集合

集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。

集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

比如,我们可以将以下不同数据结构的文档插入到集合中:
{"site":"www.baidu.com"}
{"site":"www.google.com","name":"Google"}
{"site":"www.southiu.cn","name":"南行","num":5}


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

一个collection(集合)中的所有field(域)是collection(集合)中所有document(文档)中包含的field(域) 的并集。

3.MongoDB底层原理

Mongodb的部署方案有单机部署、主从部署、副本集(主备)部署、分片部署、副本集与分片混合部署。

副本集集群

对于副本集集群,又有主和从两种角色,写数据和读数据也是不同,写数据的过程是只写到主结点中,由主 结点以异步的方式同步到从结点中:

image.png

而读数据则只要从任一结点中读取,具体到哪个结点读取是可以指定的:

mongodb不适合的场景 mongodb支持的类型_mongodb不适合的场景_02

副本集与分片混合部署

Mongodb的集群部署方案有三类角色:实际数据存储节点,配置文件存储节点和路由接入节点

  • 实际数据存储节点的作用就是存储数据
  • 路由接入节点的作用是在分片的情况下起到负载均衡的作用
  • 存储配置存储节点的作用其实存储的是片键与chunk 以及chunk 与server 的映射关系,用上面的数据表 示的配置结点存储的数据模型如下表

MongoDB的客户端直接与路由节点相连,从配置节点上查询数据,根据查询结果到实际的存储节点上查询和存储数据。

副本集与分片混合部署方式如图:

mongodb不适合的场景 mongodb支持的类型_数据_03

相同的副本集中的节点存储的数据是一样的,副本集中的节点是分为主节点、从节点、仲裁节点(非必须)三种角色。【这 种设计方案的目的,主要是为了高性能、高可用、数据备份。】 不同的副本集中的节点存储的数据是不一样,【这种设计方案,主要是为了解决高扩展问题,理论上是可以无限扩展的。】 每一个副本集可以看成一个shard(分片),多个副本集共同组成一个逻辑上的大数据节点。通过对shard上面进行逻辑分 块chunk(块),每个块都有自己存储的数据范围,所以说客户端请求存储数据的时候,会去读取config server中的映射 信息,找到对应的chunk(块)存储数据。

混合部署方式下向MongoDB写数据的流程如图:

4.MongoDB的应用场景和不适用场景

适用场景

更高的写入负载

默认情况下,MongoDB更侧重高数据写入性能,而非事务安全,MongoDB很适合业务系统中有大量“低价值”数据的场景。但是应当避免在高事务安全性的系统中使用MongoDB,除非能从架构设计上保证事务安全。

高可用性

MongoDB的复副集(Master-Slave)配置非常简洁方便,此外,MongoDB可以快速响应的处理单节点故障,自动、安全的完成故障转移。这些特性使得MongoDB能在一个相对不稳定(如云主机)的环境中,保持高可用性。

数据量很大或者未来会变得很大

依赖数据库(MySQL)自身的特性,完成数据的扩展是较困难的事,在MySQL中,当一个单表达到5-10GB时会出现明显的性能降级,此时需要通过数据的水平和垂直拆分、库的拆分完成扩展,使用MySQL通常需要借助驱动层或代理层完成这类需求。而MongoDB内建了多种数据分片的特性,可以很好的适应大数据量的需求。

基于位置的数据查询

MongoDB支持二维空间索引,因此可以快速及精确的从指定位置获取数据

表结构不明确,且数据在不断变大

在一些传统RDBMS中,增加一个字段会锁住整个数据库/表,或者在执行一个重负载的请求时会明显造成其它请求的性能降级。通常发生在数据表大于1G的时候(当大于1TB时更甚)。 因MongoDB是文档型数据库,为非结构货的文档增加一个新字段是很快速的操作,并且不会影响到已有数据。另外一个好处当业务数据发生变化时,是将不在需要由DBA修改表结构。

没有DBA支持

如果没有专职的DBA,并且准备不使用标准的关系型思想(结构化、连接等)来处理数据,那么MongoDB将会是你的首选。MongoDB对于对像数据的存储非常方便,类可以直接序列化成JSON存储到MongoDB中。 但是需要先了解一些最佳实践,避免当数据变大后,由于文档设计问题而造成的性能缺陷。

不适用场景

在某些场景下,MongoDB作为一个非关系型数据库有其局限性。MongoDB不支持事务操作,所以需要用到事务的应用建议不用MongoDB,另外MongoDB目前不支持join操作,需要复杂查询的应用也不建议使用MongoDB。

5.MongoDB安装和常用命令

安装

MongoDB 提供了 linux 各发行版本 64 位的安装包,你可以在官网下载安装包。

下载地址:https://www.mongodb.com/download-center#community

下载完安装包,并解压 tgz(以下演示的是 64 位 Linux上的安装) 。
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.11.tgz
tar -xf mongodb-linux-x86_64-rhel70-3.6.11.tgz
mv mongodb-linux-x86_64-rhel70-3.6.11 mongodb
cd mongodb/bin
# 一定注意要创建数据目录,默认路径/data/db
mkdir -p /data/db
配置环境变量(可以不配置):
vim /etc/profile
export PATH=$JAVA_HOME/bin:/root/mongodb/bin:$PATH
source /etc/profile
启动
通过配置文件方式启动
mongod --config 配置文件路径
mongod -f 配置文件路径
创建mongodb.cfg配置文件
#数据库文件位置
dbpath=/root/mongodb/singleton/data
#日志文件位置
logpath=/root/mongodb/singleton/logs/mongodb.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork=true
#绑定客户端访问的ip 0.0.0.0 不绑定ip
bind_ip=192.168.10.135
# 默认27017
port=27017
创建数据和日志目录:
mkdir /root/mongodb/singleton/data -p
mkdir /root/mongodb/singleton/logs -p
通过配置文件方式启动:
mongod -f /root/mongodb/sinleton/mongodb.cfg
连接客户端
mongo 192.168.10.135:27017
常用命令
创建数据库(如果数据库不存在,则创建数据库,否则切换到指定数据库。)
use DATABASE_NAME
如果你想查看所有数据库,可以使用 show dbs 命令:
> show dbs
admin 0.000GB
local 0.000GB
>
插入
> db.mycollection.insert({"name":"南行"})
WriteResult({ "nInserted" : 1 })
> show dbs
local 0.078GB
kkb 0.078GB
test 0.078GB
>
删除数据库
db.dropDatabase()
删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名
创建集合
MongoDB 中使用 createCollection() 方法来创建集合。
db.createCollection(name, options)> use test
switched to db test
> db.createCollection("mycollection")
{ "ok" : 1 }
>
如果要查看已有集合,可以使用 show collections 命令:
> show collections
mycollection
system.indexes
删除集合
db.collection_name.drop()> use kkb
switched to db kkb
> show tables
site
> db.site.drop()
true
> show tables
>
插入文档
db.COLLECTION_NAME.insert(document)>db.mycollection.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '南行',
url: 'http://www.kaikeba.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
>var document = {title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '南行',
url: 'http://www.kaikeba.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
}
>db.mycollection.insert(document)
删除文档
MongoDB remove()函数是用来移除集合中的数据。在执行remove()函数前先执行find()命令来判断执行的条件是否正确,这是一个比较好的习惯。
remove() 方法的基本语法格式如下所示:
db.collection.remove(
<query>,
<justOne>
)
MongoDB 是 2.6 版本以后的,语法格式如下:
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数说明:
• query :(可选)删除的文档的条件。
• justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
• writeConcern :(可选)抛出异常的级别。
接下来我们移除 title 为 ‘MongoDB 教程’ 的文档:
>db.mycollection.remove({'title':'MongoDB 教程'})
WriteResult({ "nRemoved" : 2 }) # 删除了两条数据
>db.mycollection.find()
…… # 没有数据
如果你只想删除第一条找到的记录可以设置 justOne 为 1,如下所示:
>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)
如果你想删除所有数据,可以使用以下方式(类似常规 SQL 的 truncate 命令):
>db.mycollection.remove({})
>db.mycollection.find()
查询文档
db.collection.find(query, projection)
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
>db.mycollection.find().pretty()
limit与skip方法
>db.COLLECTION_NAME.find().limit(NUMBER)
以下实例为显示查询文档中的两条记录:
> db.col.find({},{"title":1,_id:0}).limit(2)
{ "title" : "PHP 教程" }
{ "title" : "Java 教程" }
>
skip
>db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
以下实例只会显示第二条文档数据
>db.col.find({},{"title":1,_id:0}).limit(1).skip(1)
{ "title" : "Java 教程" }
>
文档排序
>db.COLLECTION_NAME.find().sort({KEY:1})
MongoDB 索引
语法
>db.collection.createIndex(keys, options)>db.col.createIndex({"title":1})
>
createIndex() 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。
>db.col.createIndex({"title":1,"description":-1})
>
查看集合索引
db.col.getIndexes()
查看集合索引大小
db.col.totalIndexSize()
删除集合所有索引
db.col.dropIndexes()
删除集合指定索引
db.col.dropIndex("索引名称")
聚合查询
>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
$group
按照城市分组对年龄进行求和
> db.LIST1.aggregate([{$group : {_id : "$city", snum : {$sum : "$age"}}}])
{ "_id" : "TJ", "snum" : 34 }
{ "_id" : "BJ", "snum" : 21 }
$sum
按照城市分组对年龄进行求和
> db.LIST1.aggregate([{$group : {_id : "$city", snum : {$sum : "$age"}}}])
{ "_id" : "TJ", "snum" : 34 }
{ "_id" : "BJ", "snum" : 21 }
按照城市分组求总个数
> db.LIST1.aggregate([{$group : {_id : "$city", sc : {$sum : 1}}}])
{ "_id" : "TJ", "sc" : 4 }
{ "_id" : "BJ", "sc" : 6 }