分布式专题(4)之MongoDB快速实战与基本原理

一、MongoDB介绍

1.1 什么是MongoDB

MongoDB是一个文档数据库(以JSON为数据模型),由C++语言编写,旨在为WEB应用提供可扩展的高性能存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,数据格式是BSON,一种类似JSON的二进制形式的存储格式,简称Binary JSON,和JSON一样支持内嵌的文档对象和数组对象,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库表单查询的绝大部分功能,而且还支持对数据建立索引。原则上Oracle和Mysql能做的事情,MongoDB都能做(包括ACID事务)。

MongoDB在数据库总排名第5,仅次于Oracle、MySQL等RDBMS,在NoSQL数据库排名首位。从诞生以来,其项目应用广度、社区活跃指数持续上升。

1.2 MongoDB vs 关系型数据库

MongoDB概念与关系型数据库(RDBMS)非常类似:

  • 数据库(database):最外层的概念,可以理解为逻辑上的名称空间,一个数据库包含多个不同名称的集合。
  • 集合(collection):相当于SQL中的表,一个集合可以存放多个不同的文档。
  • 文档(document):一个文档相当于数据表中的一行,由多个不同的字段组成。
  • 字段(field):文档中的一个属性,等同于列(column)。
  • 索引(index):独立的检索式数据结构,与SQL概念一致。
  • _id:每个文档中都拥有一个唯一的_id字段,相当于SQL中的主键(primary key)。
  • 视图(view):可以看作一种虚拟的(非真实存在的)集合,与SQL中的视图类似。从MongoDB 3.4版本开始提供了视图功能,其通过聚合管道技术实现。
  • 聚合操作($lookup):MongoDB用于实现"类似"表连接(tablejoin)的聚合操作符。

尽管这些概念大多与SQL标准定义类似,但MongoDB与传统RDBMS仍然存在不少差异,包括:

  • 半结构化,在一个集合中,文档所拥有的字段并不需要是相同的,而且也不需要对所用的字段进行声明。因此,MongoDB具有很明显的半结构化特点。除了松散的表结构,文档还可以支持多级的嵌套、数组等灵活的数据类型,非常契合面向对象的编程模型。
  • 弱关系,MongoDB没有外键的约束,也没有非常强大的表连接能力。类似的功能需要使用聚合管道技术来弥补。

1.3 MongoDB技术优势

MongoDB基于灵活的JSON文档模型,非常适合敏捷式的快速开发。与此同时,其与生俱来的高可用、高水平扩展能力使得它在处理海量、高并发的数据应用时颇具优势。

  • JSON 结构和对象模型接近,开发代码量低
  • JSON的动态模型意味着更容易响应新的业务需求
  • 复制集提供99.999%高可用
  • 分片架构支持海量数据和无缝扩容

简单直观:从错综复杂的关系模型到一目了然的对象模型:

快速:最简单快速的开发方式

灵活:快速响应业务变化

原生的高可用:

横向扩展能力

1.4 MongoDB应用场景

从目前阿里云 MongoDB 云数据库上的用户看,MongoDB 的应用已经渗透到各个领域:

  • 游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新;
  • 物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来;
  • 社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能;
  • 物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析;
  • 视频直播,使用 MongoDB 存储用户信息、礼物信息等;
  • 大数据应用,使用云数据库MongoDB作为大数据的云存储系统,随时进行数据提取分析,掌握行业动态。|

国内外知名互联网公司都在使用MongoDB:

1.4.1 如何判断当前业务是否适合使用MongoDB

没有某个业务场景必须要使用MongoDB才能解决,但使用MongoDB通常能让你以更低的成本解决问题。如果你不清楚当前业务是否适合使用MongoDB,可以通过做几道选择题来辅助决策。

只要有一项需求满足就可以考虑使用MongoDB,匹配越多,选择MongoDB越合适。

二、MongoDB环境搭建

2.1 linux安装MongoDB

环境准备:

  • linux系统: centos7
  • 安装MongoDB社区版
bash 复制代码
#如何查看linux版本
[root@hadoop01 soft]# cat /etc/redhat-release 
CentOS Linux release 7.9.2009 (Core)

#下载MongoDB
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-6.0.5.tgz
tar -zxvf mongodb-linux-x86_64-rhel70-6.0.5.tgz


#创建dbpath和logpath
mkdir -p /mongodb/data /mongodb/log  
#进入mongodb目录,启动mongodb服务
bin/mongod --port=27017 --dbpath=/mongodb/data --logpath=/mongodb/log/mongodb.log \
--bind_ip=0.0.0.0 --fork

--dbpath :指定数据文件存放目录

--logpath :指定日志文件,注意是指定文件不是目录

--logappend :使用追加的方式记录日志

--port:指定端口,默认为27017

--bind_ip:默认只监听localhost网卡

--fork: 后台启动

--auth: 开启认证模式

添加环境变量:修改/etc/profile,添加环境变量,方便执行MongoDB命令,然后执行source /etc/profile 重新加载环境变量

bash 复制代码
export MONGODB_HOME=/usr/local/soft/mongodb
PATH=$PATH:$MONGODB_HOME/bin  

利用配置文件启动服务:编辑/mongodb/conf/mongo.conf文件,内容如下:

bash 复制代码
systemLog:
  destination: file
  path: /mongodb/log/mongod.log # log path
  logAppend: true
storage:
  dbPath: /mongodb/data # data directory
  engine: wiredTiger  #存储引擎
  journal:            #是否启用journal日志
    enabled: true
net:
  bindIp: 0.0.0.0
  port: 27017 # port
processManagement:
  fork: true

注意:一定要yaml格式:

bash 复制代码
mongod -f /mongodb/conf/mongo.conf

2.2 关闭MongoDB 服务

bash 复制代码
mongod --port=27017 --dbpath=/mongodb/data --shutdown 

关闭:方式一

关闭方式二: 进入mongosh

bash 复制代码
use admin
# 关闭MongoDB server 服务
db.shutdownServer()

2.3 mongosh使用

mongosh是MongoDB的交互式JavaScript Shell界面,它为系统管理员提供了强大的界面,并为开发人员提供了直接测试数据库查询和操作的方法。

注意:MongoDB 6.0 移除了mongo,使用mongosh

mongosh下载地址:MongoDB Shell Download | MongoDB

bash 复制代码
#centos7 安装mongosh
wget https://downloads.mongodb.com/compass/mongodb-mongosh-1.8.0.x86_64.rpm
yum install -y mongodb-mongosh-1.8.0.x86_64.rpm

# 连接mongodb server端
mongosh --host=192.168.65.206 --port=27017 
mongosh 192.168.65.206:27017
# 指定uri方式连接
mongosh mongodb://192.168.65.206:27017/test

--port:指定端口,默认为27017

--host:连接的主机地址,默认127.0.0.1

2.4 mongosh常用命令

|---------------------------------|--------------------|
| 命令 | 说明 |
| show dbs | show databases | 显示数据库列表 |
| use 数据库名 | 切换数据库,如果不存在创建数据库 |
| db.dropDatabase() | 删除数据库 |
| show collections | show tables | 显示当前数据库的集合列表 |
| db.集合名.stats() | 查看集合详情 |
| db.集合名.drop() | 删除集合 |
| show users | 显示当前数据库的用户列表 |
| show roles | 显示当前数据库的角色列表 |
| show profile | 显示最近发生的操作 |
| load("xxx.js") | 执行一个JavaScript脚本文件 |
| exit | quit | 退出当前shell |
| help | 查看mongodb支持哪些命令 |
| db.help() | 查询当前数据库支持的方法 |
| db.集合名.help() | 显示集合的帮助信息 |
| db.version() | 查看数据库版本 |

数据库操作;

bash 复制代码
#查看所有库
show dbs
# 切换到指定数据库,不存在则创建
use test
# 删除当前数据库  
db.dropDatabase()

集合操作:

bash 复制代码
#查看集合
show collections
#创建集合
db.createCollection("emp")
#删除集合
db.emp.drop()

创建集合语法:

bash 复制代码
db.createCollection(name, options)

options参数:

|--------|----|----------------------------------------------------------|
| 字段 | 类型 | 描述 |
| capped | 布尔 | (可选)如果为true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。 |
| size | 数值 | (可选)为固定集合指定一个最大值(以字节计)。 如果 capped 为 true,也需要指定该字段。 |
| max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |

三、MongoDB文档操作

SQL to MongoDB Mapping Chart :SQL to MongoDB Mapping Chart - MongoDB Manual v8.0

3.1 插入文档

MongoDB提供了以下方法将文档插入到集合中:

  • db.collection.insertOne ():将单个文档插入到集合中。
  • db.collection.insertMany ():将多个文档插入到集合中。

3.1.1 新增单个文档

  • insertOne: 用于向集合中插入一条文档数据,支持writeConcern。语法如下:
bash 复制代码
db.collection.insertOne(
   <document>,
   {
      writeConcern: <document>
   }
)


db.emps.insertOne(
   { name: "fox", age: 35},
   {
      writeConcern: { w: "majority", j: true, wtimeout: 5000 }
   }
)

writeConcern 是 MongoDB 中用来控制写入确认的选项。以下是 writeConcern 参数的一些常见选项:

  • w:指定写入确认级别。如果指定为数字,则表示要等待写入操作完成的节点数。如果指定为 majority,则表示等待大多数节点完成写入操作。默认为 1,表示等待写入操作完成的节点数为 1。
  • j:表示写入操作是否要求持久化到磁盘。如果设置为 true,则表示写入操作必须持久化到磁盘后才返回成功。如果设置为 false,则表示写入操作可能在数据被持久化到磁盘之前返回成功。默认为 false。
  • wtimeout:表示等待写入操作完成的超时时间,单位为毫秒。如果超过指定的时间仍然没有返回确认信息,则返回错误。默认为 0,表示不设置超时时间。

3.1.2 批量新增文档

  • insertMany:向指定集合中插入多条文档数据
bash 复制代码
db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>      
   }
)
  • writeConcern:写入确认选项,可选。
  • ordered:指定是否按顺序写入,默认 true,按顺序写入。

3.2 查询文档

查询集合中的若干文档,语法格式如下:

bash 复制代码
db.collection.find(query, projection)
  • query :可选,使用查询操作符指定查询条件
  • projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。投影时,_id为1的时候,其他字段必须是1;_id是0的时候,其他字段可以是0;如果没有_id字段约束,多个其他字段必须同为0或同为1。

如果查询返回的条目数量较多,mongosh则会自动实现分批显示。默认情况下每次只显示20条,可以输入it命令读取下一批。

3.2.1 查询集合中的第一个文档

语法格式如下:

bash 复制代码
db.collection.findOne(query, projection)

如果你需要以易读的方式来读取数据,可以使用pretty)方法,语法格式如下:

bash 复制代码
db.collection.find().pretty()

3.2.2 条件查询

查询条件对照表:

|----------|----------------|
| SQL | MQL |
| a = 1 | {a: 1} |
| a <> 1 | {a: {ne: 1}} | | a \> 1 | {a: {gt: 1}} |
| a >= 1 | {a: {gte: 1}} | | a \< 1 | {a: {lt: 1}} |
| a | {a: {$lte: 1}} |

查询逻辑对照表:

|-----------------|-----------------------------------------|
| SQL | MQL |
| a = 1 AND b = 1 | {a: 1, b: 1}或{and: \[{a: 1}, {b: 1}\]} | | a = 1 OR b = 1 | {or: [{a: 1}, {b: 1}]} |
| a IS NULL | {a: {exists: false}} | | a IN (1, 2, 3) | {a: {in: [1, 2, 3]}} |

查询逻辑运算符:

  • $lt: 存在并小于
  • $lte: 存在并小于等于
  • $gt: 存在并大于
  • $gte: 存在并大于等于
  • $ne: 不存在或存在但不等于
  • $in: 存在并在指定数组中
  • $nin: 不存在或不在指定数组中
  • $or: 匹配两个或多个条件中的一个
  • $and: 匹配全部条件
bash 复制代码
#查询带有nosql标签的book文档:
db.books.find({tag:"nosql"})
#按照id查询单个book文档:
db.books.find({_id:ObjectId("61caa09ee0782536660494d9")})
#查询分类为"travel"、收藏数超过60个的book文档:
db.books.find({type:"travel",favCount:{$gt:60}})

3.3 更新文档

MongoDB提供了以下方法来更新集合中的文档:

  • db.collection.updateOne ():即使多个文档可能与指定的筛选器匹配,也只会更新第一个匹配的文档。
  • db.collection.updateMany ():更新与指定筛选器匹配的所有文档。

更新操作符:

|-----------|-------------------------------------------------|-------------------------|
| 操作符 | 格式 | 描述 |
| set | {set:{field:value}} | 指定一个键并更新值,若键不存在则创建 |
| unset | {unset : {field : 1 }} | 删除一个键 |
| inc | {inc : {field : value } } | 对数值类型进行增减 |
| rename | {rename : {old_field_name : new_field_name } } | 修改字段名称 |
| push | { push : {field : value } } | 将数值追加到数组中,若数组不存在则会进行初始化 |
| pushAll | {pushAll : {field : value_array }} | 追加多个值到一个数组字段内 |
| pull | {pull : {field : _value } } | 从数组中删除指定的元素 |
| addToSet | {addToSet : {field : value } } | 添加元素到数组中,具有排重功能 |
| pop | {pop : {field : 1 }} | 删除数组的第一个或最后一个元素 |

3.4 删除文档

官方推荐使用 deleteOne() 和 deleteMany() 方法删除文档,语法格式如下:

bash 复制代码
db.books.deleteOne ({ type:"novel" })  //删除 type等于novel 的一个文档
db.books.deleteMany ({})  //删除集合下全部文档
db.books.deleteMany ({ type:"novel" })  //删除 type等于 novel 的全部文档

注意:remove、deleteMany命令需要对查询范围内的文档逐个删除,如果希望删除整个集合,则使用drop命令会更加高效

四、MongoDB数据类型详解

4.1 BSON协议与数据类型

JSON是当今非常通用的一种跨语言Web数据交互格式,属于ECMAScript标准规范的一个子集。JSON(JavaScript Object Notation, JS对象简谱)即JavaScript对象表示法,它是JavaScript对象的一种文本表现形式。

JSON是当今非常通用的一种跨语言Web数据交互格式,属于ECMAScript标准规范的一个子集。JSON(JavaScript Object Notation, JS对象简谱)即JavaScript对象表示法,它是JavaScript对象的一种文本表现形式。

JSON只定义了6种数据类型:

  • string: 字符串
  • number : 数值
  • object: JS的对象形式,用{key:value}表示,可嵌套
  • array: 数组,JS的表示方式[value],可嵌套
  • true/false: 布尔类型
  • null: 空值

大多数情况下,使用JSON作为数据交互格式已经是理想的选择,但是JSON基于文本的解析效率并不是最好的,在某些场景下往往会考虑选择更合适的编/解码格式,一些做法如:

  • 在微服务架构中,使用gRPC(基于Google的Protobuf)可以获得更好的网络利用率。
  • 分布式中间件、数据库,使用私有定制的TCP数据包格式来提供高性能、低延时的计算能力。

BSON由10gen团队设计并开源,目前主要用于MongoDB数据库。BSON(Binary JSON)是二进制版本的JSON,其在性能方面有更优的表现。BSON在许多方面和JSON保持一致,其同样也支持内嵌的文档对象和数组结构。二者最大的区别在于JSON是基于文本的,而BSON则是二进制(字节流)编/解码的形式。在空间的使用上,BSON相比JSON并没有明显的优势。

MongoDB在文档存储、命令协议上都采用了BSON作为编/解码格式,主要具有如下优势:

  • 类JSON的轻量级语义,支持简单清晰的嵌套、数组层次结构,可以实现模式灵活的文档结构。
  • 更高效的遍历,BSON在编码时会记录每个元素的长度,可以直接通过seek操作进行元素的内容读取,相对JSON解析来说,遍历速度更快。
  • 更丰富的数据类型,除了JSON的基本数据类型,BSON还提供了MongoDB所需的一些扩展类型,比如日期、二进制数据等,这更加方便数据的表示和操作。

4.2 BSON的数据类型

MongoDB中,一个BSON文档最大大小为16M,文档嵌套的级别不超过100:BSON Types - MongoDB Manual v6.0

|----------------------------|--------|-----------------------|----------------------------|
| Type | Number | Alias | Notes |
| Double | 1 | "double" | |
| String | 2 | "string" | |
| Object | 3 | "object" | |
| Array | 4 | "array" | |
| Binary data | 5 | "binData" | 二进制数据 |
| Undefined | 6 | "undefined" | Deprecated. |
| ObjectId | 7 | "objectId" | 对象ID,用于创建文档ID |
| Boolean | 8 | "bool" | |
| Date | 9 | "date" | |
| Null | 10 | "null" | |
| Regular Expression | 11 | "regex" | 正则表达式 |
| DBPointer | 12 | "dbPointer" | Deprecated. |
| JavaScript | 13 | "javascript" | |
| Symbol | 14 | "symbol" | Deprecated. |
| JavaScript code with scope | 15 | "javascriptWithScope" | Deprecated in MongoDB 4.4. |
| 32-bit integer | 16 | "int" | |
| Timestamp | 17 | "timestamp" | |
| 64-bit integer | 18 | "long" | |
| Decimal128 | 19 | "decimal" | New in version 3.4. |
| Min key | -1 | "minKey" | 表示一个最小值 |
| Max key | 127 | "maxKey" | 表示一个最大值 |

4.3 ObjectId生成器

MongoDB集合中所有的文档都有一个唯一的_id字段,作为集合的主键。在默认情况下,_id字段使用ObjectId类型,采用16进制编码形式,共12个字节。

为了避免文档的_id字段出现重复,ObjectId被定义为3个部分:

  • 4字节表示Unix时间戳(秒)。
  • 5字节表示随机数(机器号+进程号唯一)。
  • 3字节表示计数器(初始化时随机)。

大多数客户端驱动都会自行生成这个字段,比如MongoDB Java Driver会根据插入的文档是否包含_id字段来自动补充ObjectId对象。这样做不但提高了离散性,还可以降低MongoDB服务器端的计算压力。在ObjectId的组成中,5字节的随机数并没有明确定义,客户端可以采用机器号、进程号来实现:

相关推荐
数据智能老司机18 小时前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构
数据智能老司机18 小时前
CockroachDB权威指南——开始使用
数据库·分布式·架构
松果猿18 小时前
空间数据库学习(二)—— PostgreSQL数据库的备份转储和导入恢复
数据库
无名之逆19 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
s91236010119 小时前
rust 同时处理多个异步任务
java·数据库·rust
数据智能老司机19 小时前
CockroachDB权威指南——CockroachDB 架构
数据库·分布式·架构
IT成长日记19 小时前
【Kafka基础】Kafka工作原理解析
分布式·kafka
hzulwy19 小时前
Redis常用的数据结构及其使用场景
数据库·redis
程序猿熊跃晖19 小时前
解决 MyBatis-Plus 中 `update.setProcInsId(null)` 不生效的问题
数据库·tomcat·mybatis
州周21 小时前
kafka副本同步时HW和LEO
分布式·kafka