数据库
🗒️MongoDB入门
00 min
2023-6-14
2023-8-29
type
status
date
slug
summary
tags
category
icon
password
😀
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。

一、 概述

1.1、什么是MongoDB?

MongoDB是一种关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是一种类似于JSON的BSON格式数据,因此可以存储比较复杂的数据类型。MongoDB中的记录是一个文档,是一个由字段和值对(field:value)组成的数据结构,MongoDB文档类似于JSON对象,即一个文档认为就是一个对象,字段的数据类型是字符型,它的值除了使用基本的一些类型外,还可以包括其他文档,普通数组和文档数组。
SQL术语/概念
MongoDB术语/概念
解释/说明
database
database
数据库
table
collection
数据库表/集合
row
document
数据记录行/文档
column
field
数据字段/域
index
index
索引
table joins
表连接,MongoDB不支持
primary key
primary key
主键,MongoDB自动将_id字段设置为主键
MongoDB数据模型是面向文档的,所谓文档就是一种类似于JSON的结构,可以理解为MongoDB数据库中存在的是各种各样的JSON(BSON)
  • 数据库(database):数据库是一个仓库,存储集合(collection)。
    • admin:类似于root数据库,如果将用户添加至admin数据库将获取所有数据库的权限,其中一些比如查找所有数据库、关闭服务器的服务端命令只能从这里运行。
    • local:存储当前服务器所有本地集合的数据库,永远不可以复制。
    • config:主要是存储分片等信息
  • 集合(collection):类似于数组,在集合中存放文档。
  • 文档(document):文档型数据库的最小单元,通常情况下,存储和操作的内容都是文档。
  • docker run --name one-api -d --restart always -p 20117:3000 -e TZ=Asia/Shanghai -v /www/wwwroot/one-api:/data justsong/one-api

1.2、MongoDB的数据类型

MongoDB文档存储是使用BSON类型,BSON是二进制序列化的形式。类如JSON,同样支持内嵌各种类型。
MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中
String
字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。
Integer
整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。
Boolean
布尔值。用于存储布尔值(真/假)。
Double
双精度浮点值。用于存储浮点值。
Min/Max keys
将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。
Array
用于将数组或列表或多个值存储为一个键。
Timestamp
时间戳。记录文档修改或添加的具体时间。
Object
用于内嵌文档。
Null
用于创建空值。
Symbol
符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。
Date
日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。
Object ID
对象 ID。用于创建文档的 ID。  (每个文档都有)
Binary Data
二进制数据。用于存储二进制数据。
Code
代码类型。用于在文档中存储 JavaScript 代码。
Regular expression
正则表达式

ObjectId

ObjectId类似于唯一主键,可以很快的去生成和排序,包含12bytes,其中含义是:
  • 前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时
  • 接下来的 3 个字节是机器标识码
  • 紧接的两个字节由进程 id 组成 PID
  • 最后三个字节是随机数
    • notion image
MongoDB中存储的文档必须有一个_id键,该键的值可以是任何类型的,默认是个ObjectID对象。ObjectID保存了创建的时间戳,就不需要为文档保存时间戳字段,可以通过getTimestamp函数来获取文档的创建时间。

时间戳

BSON有一个特殊的时间戳类型用于MongoDB内部使用,与普通的日期类型不相关。时间戳是一个64位的值,其中前32位是一个time_t值(与Unix新纪元相差的秒数),后32位是在某秒中操作的一个递增的序数。

1.3、MongoDB的特点

1、高性能

MongoDB可以提供高性能的数据持久性,对嵌入式数据模型的支持减少了数据库系统上的IO活动。
  • 索引支持更快的查询,并且包含嵌入式文档和数组的键。
  • 文本索引解决搜索的需求;
  • TTL索引解决历史数据自动过期的需求;
  • 地理位置索引可用于构建各种 O2O 应用;

2、高可用

MongoDB的复制工具称为副本集(reolica set),它包含提供自动故障转移和数据冗余。

3、高扩展

MongoDB提供了水平可扩展性作为其核心功能的一部分。
分片将数据分布在一组集群的机器上。(海量数据存储、服务能力水平扩展)
从3.4起,MongoDB支持基于片键创建数据区域,在一个平衡的集群中,MongoDB将一个区域所覆盖的读写只定向到该区域内的那些片。

4、丰富的查询支持

MongoDB支持丰富的查询语言,支持读写(CRUD)操作、比如数据聚合、文本搜索、地理空间查询等。

5、其他

如动态模式、灵活的文档模型。

1.4、MongoDB的应用场景

传统的关系型数据库,在数据操作的“三高”需求前会有“力不从心”的感觉。
三高是高并发高性能高可用
  • High Performance: 对数据库的高并发读写的要求
  • High Storage: 对海量数据的高效率存储和访问的需求
  • High Scalability && High Available: 对数据的高扩展性和高可用性的需求
在具体的应用场景上,
  1. 游戏场景:可以使用MongoDB存储游戏用户信息、装备、积分等,直接以内嵌文档的形式存储,方便查询、更新。
  1. 物流场景:使用MongoDB存储订单信息、订单状态、物流信息,订单状态在运送过程中飞速迭代,以MongoDB内嵌数组的形式来存储,一次查询就能将订单所有的变更查出来。
  1. 社交场景:MongoDB存储用户信息,朋友圈信息,通过地理位置索引实现附近的人、定位功能。
  1. 物联网场景:使用MongoDB存储设备信息、设备汇报的日志信息、并对这些信息进行多维度分析。
  1. 视频直播:使用MongoDB存储用户信息、点赞互动信息。

二、基本常用命令

2.1、连接

通过使用MongoDB Shell连接MongoDB服务器,标准的URI连接语法如下
  • mongodb:// 这是固定的格式,必须要指定。
  • username:password@ 可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登录这个数据库
  • host1 必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。
  • portX 可选的指定端口,如果不填,默认为27017
  • /database 如果指定username:password@,连接并验证登录指定数据库。若不指定,默认打开 test 数据库。
  • ?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&或;(分号)隔开

2.2、数据库操作

操作
语法
查看所有数据库
show dbs;show databases;
查看当前数据库
db;
切换到某数据库 (若数据库不存在则创建数据库)
use <db_name>;
删除当前数据库
db.dropDatabase();
创建数据库后查看会发现,刚刚创建的数据库并没有显现出来,是由于MongoDB的存储机制决定的。
执行use testDB命令的时候,如果testDB数据库不存在则创建该数据库。新建的数据库中内容为空,此时是存放在内存之中。当数据库中存在一个collection之后,会自动持久化到磁盘中。
当向数据库中插入数据后,数据库就持久化到磁盘中,可以通过show dbs查看。

2.3、集合操作

集合就是MongoDB文档组,类似于RDBMS(关系数据库管理系统)中的表格。
集合存在于数据库中,集合没有固定的结构,也就是说对集合可以插入不同格式和类型的数据。

合法的集合名

  • 集合名不能是空字符串“”。
  • 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
  • 集合名不能以“system.”开头,这是为系统保留的前缀。
  • 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。
创建集合
options 可以是如下参数:
字段
类型
描述
capped
布尔
(可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。 当该值为 true 时,必须指定 size 参数。
autoIndexId
布尔
3.2 之后不再支持该参数。(可选)如为 true,自动在 _id 字段创建索引。默认为 false。
size
数值
(可选)为固定集合指定一个最大值,即字节数。 如果 capped 为 true,也需要指定该字段。
max
数值
(可选)指定固定集合中包含文档的最大数量。
查询集合
删除集合

2.4、文档基本CRUD

文档的数据结构和JSON基本一样,所有存储在集合中的数据都是BSON格式。BSON是一种类似于JSON的二进制形式的存储格式,是Binary JSON的简称。

2.4.1、创建 CREATE

使用db.<collection_name>.insertOne()向集合中插入一个新文档,参数一个json格式的文档,语法格式如下
使用db.<collection_name>.insertMany()向集合中添加多个文档,参数为json文档数组,语法格式如下
参数说明:
  • document:要写入的文档。
  • writeConcern:写入策略,默认为 1,即要求确认写操作,0 是不要求。
  • ordered:指定是否按顺序写入,默认 true,按顺序写入
可以通过js函数方式批量插入文档:1.先创建数组。2.将数据放入数组中。3.一次insert到集合中。
注:当我们向collection中插入document文档时, 如果没有给文档指定_id属性, 那么数据库会为文档自动添加_id属性, 并且值类型是ObjectId(blablabla), 就是文档的唯一标识, 类似于 relational database 里的primary key
数据批量插入失败
在批量插入数据时,其中某一条数据插入失败,将会终止插入,前面已经插入成功的数据不会回滚掉。在进行批量插入的时候,可以使用try catch进行异常捕捉处理。

2.4.2、查询 READ

  • 使用db.<collection_name>.find()方法对集合进行查询,接受一个json格式的查询条件,返回的是一个数组。
  • 使用db.<collection_name>.findOne()方法查询集合中符合条件的第一个文档,返回的是一个对象。
可以在查询条件后面再跟上需要查询的字段,1表示显示指定的字段,其中_id是默认显示的,可以指定0表示强制不显示。

2.4.3、更新 UPDATE

  • 使用db.<collection_name>.updateOne(<filter>, <update>, <options>)方法修改一个匹配<filter>条件的文档
  • 使用db.<collection_name>.updateMany(<filter>, <update>, <options>)方法修改所有匹配<filter>条件的文档
  • 使用db.<collection_name>.replaceOne(<filter>, <update>, <options>)方法替换一个匹配 <filter>条件的文档
  • db.<collection_name>.update(查询对象, 新对象)默认情况下会使用新对象替换旧对象
覆盖修改,会将其他的值清除
局部修改,只修改所修改的部分
$set修改文档中的制定属性
db.<collection_name>.replaceOne()方法替换除_id属性外的所有属性,其<update>参数应为一个全新的文档。
批量修改
在后面添加{multi: true}即可

2.4.4、删除 DELETE

  • db.collection.remove()通过添加删除规则进行删除
  • 使用 db.collection.deleteMany() 方法删除所有匹配的文档.
  • 使用 db.collection.deleteOne() 方法删除单个匹配的文档.
  • db.collection.drop()
  • db.dropDatabase()
只删除一条记录

s2.5、文档排序和投影(sort&projection)

2.5.1、排序 sort

在查询文档内容的时候,默认是按照_id进行排序的,可以使用$sort更改文档排序规则。
  • 1AES - ascend - 升序
  • 1 - descend - 降序
:skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先sort(), 然后是skip(),最后是显示的limit()。

2.5.2、投影 Projection

在对文档进行查询时,不需要展示所有字段,只需要id或者用户名时,可以对文档进行“投影”
  • 1 - display
  • 0 - dont display

2.6、分页查询

2.6.1、统计查询

统计查询使用count()方法,语法如下:

2.6.2、分页列表查询

通过limit()方法来读取指定数量的数据,使用skip()方法来跳过指定数量的数据。

2.6.3、排序查询

sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用1和-1来指定排序的方式,1为升序排列,而-1是用于降序排列。

2.7、常用命令小结

三、文档间的对应关系

文档间可以通过嵌入和引用来建立联系。
关系可以是:
  • 一对一 (One To One)
  • 一对多/多对一(one to many / many to one)
  • 多对多 (Many To Many)

3.1、一对一

在MongoDB中可以通过内嵌文档的形式体现出一对一的关系,比如夫妻:
一个文档对象一旦被嵌入到另一个文档对象中就绝不可能再被嵌入到其他文档对象中,因此可以体现出一对一的关系

3.2、一对多/多对一

用户与地址的关系,一个用户可以拥有多个地址。
嵌入式关系
以上数据结构的缺点是:如果用户和用户地址在不断增加,数据量不断变大,会影响读写性能。
引入式关系
将用户数据文档和用户地址数据文档分开,通过引用文档的ID字段来建立关系。
查询的话需要两次查询,第一次查询用户地址的对象id(ObjectId),第二次通过查询的id获取用户的详细地址休息

3.3、多对多

关系数据库中处理多对多关系的时候采用的方法一般是将两张表的主键抽取出来,放到一张单独的关系表中,将两张表的主键作为这张关系表的外键,每次进行关联查询的时候都先在关系表中找到对应表的主键。
MongoDB中处理多对多关系有点类似于一对多的情况,是通过增加一些冗余的字段来记录关系。
上一篇
Docker的基本使用
下一篇
数据结构基础