分布式专题(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字节的随机数并没有明确定义,客户端可以采用机器号、进程号来实现:

相关推荐
倔强的石头_3 小时前
kingbase备份与恢复实战(二)—— sys_dump库级逻辑备份与恢复(Windows详细步骤)
数据库
jiayou641 天前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
李广坤2 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
初次攀爬者3 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
爱可生开源社区3 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
AI全栈实验室3 天前
MongoDB迁移金仓踩了5个坑,最后一个差点回滚
mongodb
随逸1773 天前
《从零搭建NestJS项目》
数据库·typescript
加号34 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql
シ風箏4 天前
MySQL【部署 04】Docker部署 MySQL8.0.32 版本(网盘镜像及启动命令分享)
数据库·mysql·docker
李慕婉学姐4 天前
Springboot智慧社区系统设计与开发6n99s526(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端