MongoDB 非关系型数据库
# MongoDB 非关系型数据库
# 1. 数据库简介
# 1.1 数据库是什么
数据库(DataBase)是按照数据结构来组织、存储和管理数据的仓库。
# 1.2 为什么要使用数据库
我们的程序都是在内存中运行的,一旦程序运行结束或者计算机断电,程序运行中的数据都会丢失。所以我们就需要将一些程序运行的数据持久化到硬盘之中,以确保数据的安全性。而数据库就是数据持久化的最佳选择。说白了,数据库就是存储数据的仓库。
# 1.3 数据库的分类
# 1.3.1 关系型数据库(RDBS)
- 代表有:MySQL、Oracle、DB2、SQL Server...
- 特点:关系紧密,表结构
- 优点:
- 易于维护:都是使用表结构,格式一致;
- 使用方便:SQL 结构化查询通用,可用于复杂查询;
- 高级查询:可用于一个表以及多个表之间非常复杂的查询。
- 缺点:
- 读写性能比较差,尤其是海量数据的高效率读写;
- 有固定的表结构,字段不可随意更改,灵活度稍欠;
- 高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。
# 1.3.2 非关系型数据库(NoSQL)
- 代表有:MongoDB、Redis...
- 特点:关系不紧密,文档存储,有键值对
- 优点:
- 格式灵活:存储数据的格式可以是key,value形式。
- 速度快:nosql可以内存作为载体,而关系型数据库只能使用硬盘;
- 易用:nosql数据库部署简单。
- 缺点:
- 不支持sql,学习和使用成本较高;
- 不支持事务;
- 复杂查询时语句过于繁琐。
# 2. MongoDB 的简介和安装
# 2.1 MongoDB 简介
- MongoDB 是为 快速开发互联网 Web 应用而设计的数据库系统。
- MongoDB 的设计目标是极简、灵活、作为Web应用栈的一部分。
- MongoDB 的数据模型是面向文档的,所谓文档是一种类似于
JSON
的结构,简单理解 MongoDB 这个数据库中存的是各种各样的JSON。(BSON
)
# 2.2 MongoDB 安装和基本配置
# 2.2.1 MongoDB 安装
- 下载安装 MongoDB 数据库系统,安装好后需要配置环境变量,在系统高级设置中添加 MongoDB 安装路径下的
bin
的路径即可。(一般都是安装在C盘,无法修改。) - 在c盘根目录创建文件夹
C:\data\db
- 打开命令行窗口输入
mongod
启动数据库服务器 - 打开一个新的命令行窗口输入
mongo
启动数据库的客户端
# 2.2.2 MongoDB 服务器的启动
- 服务器负责在计算机创建数据库,使用数据库需要先启动服务器
- MongoDB的默认端口号
27017
- 可以通过
--port
来指定端口号 - 端口号尽量使用四位以上,不要超过最大端口号65535
- 不能使用其他服务占用的端口号
- 可以通过
- MongoDB 数据库默认会存放在C盘根目录下的
data/db
,可以通过--dbpath
指令来指定数据库的目录
结合使用:
mongod --dbpath C:\Users\web\Desktop\database --port 12345
[!warning] 注意:目前为止,启动服务的命令行窗口不能关闭。
# 2.2.3 MongoDB 客户端
- 我们通过客户端来管理数据库
- 在 CMD 输入
mongo
来启动客户端
# 2.3 将 MongoDB 设置为 windows 系统服务
每次使用服务都要手动启动依次服务器,且启动服务窗口不能关闭。这里我们将将 MongoDB 设置为 windows 系统服务,使其开机自启。
- 在c盘根目录创建如下文件夹
C:\data\log C:\data\db
1
2 - 在MongoDB的安装目录添加一个配置文件
mongod.cfg
。
其中,目录位置如下(根据自己数据库版本确定):// 目录 C:\Program Files\MongoDB\Server\4.4
1
2mongod.cfg
的文件内容如下:systemLog: destination: file path: c:\data\log\mongod.log storage: dbPath: c:\data\db net: port: 27017
1
2
3
4
5
6
7 - 以管理员身份打开命令行,执行以下指令(注意版本号根据自己的修改):
sc.exe create MongoDB binPath= "\"C:\Program Files\MongoDB\Server\3.2\bin\mongod.exe\" --service --config=\"C:\Program Files\MongoDB\Server\3.2\mongod.cfg\"" DisplayName= "MongoDB" start= "auto"
1 - 打开系统服务器,启动名为 MongoDB 的服务,将其启动方式设置为自动。
- 如果无法启动服务,在管理员的命令行窗口中输入如下指令,然后重复步骤1。
sc delete MongoDB
1
# 2.4 安装 MongoDB 图形化工具
数据库图形化管理工具 极大地方便了数据库的操作与管理,推荐的 MongoDB 图形化管理工具 有:
# 2.5 常用端口号总结
端口号:1-65535
,不建议使用 1--199
的端口号,这些是预留给系统的,一般使用 4 位的,4 位的也不要用 1 开头的。
常见端口号:
21
端口:FTP 文件传输服务22
端口:SSH 端口23
端口:TELNET 终端仿真服务25
端口:SMTP 简单邮件传输服务53
端口:DNS 域名解析服务80
端口:HTTP 超文本传输服务110
端口:POP3 “邮局协议版本3”使用的端口443
端口:HTTPS 加密的超文本传输服务1433
端口:MS SQL*SERVER数据库 默认端口号1521
端口:Oracle数据库服务1863
端口:MSN Messenger的文件传输功能所使用的端口3306
端口:MYSQL 默认端口号3389
端口:Microsoft RDP 微软远程桌面使用的端口5631
端口:Symantec pcAnywhere 远程控制数据传输时使用的端口5632
端口:Symantec pcAnywhere 主控端扫描被控端时使用的端口5000
端口:MS SQL Server使用的端口27017
端口:MongoDB 实例默认端口
# 3. MongoDB 的使用
# 3.1 MongoDB 中的基本概念
- 数据库(database)
数据库是一个仓库,在仓库中可以存放集合。 - 集合(collection)
集合类似于JS中的数组,在集合中可以存放文档。 说白了,集合就是一组文档。 - 文档(document)
文档数据库中的最小单位,我们存储和操作的内容都是文档。类似于JS中的对象,在MongoDB中每一条数据都是一个文档。
和 MySQL 的对比:
MySQL | MongoDB | 描述 |
---|---|---|
数据库 | 数据库 | 一个数据库文件 |
表 | 集合 | 关系型数据库:一张表,非关系型:一个集合 |
字段 | 字段 | 每列的头,在关系型数据库中,某些字段是唯一标识,则称为主键 |
一条数据 | 一条文档 | 一行数据 |
# 3.2 命令行基本命令
- 显示所有的数据库
show dbs show databases
1
2 - 切换到指定的数据库
use 数据库名
1 - 显示当前所在的数据库
db
1 - 删除当前数据库
db.dropDatabase()
1 - 显示当前数据库中的所有集合
show collections
1 - 删除当前集合
db.collection.drop()
1
在 MongoDB,数据库和集合都不需要创建,当 我们向集合或数据库中第一次插入文档时,集合和数据库会自动创建。
- 向集合中插入文档如:
db.<collection>.insert(doc)
1db.stus.insert({name:"sunwukong",age:18})
1 - 查询集合中的文档如:
db.<collection>.find()
1db.stus.find()
1
# 3.3 MongoDB 原生 CRUD(增删改查)
# 1. C-creat(新增数据)
db.集合名.insert(文档对象)
db.集合名.insertOne(文档对象)
db.集合名.insertMany([文档对象,文档对象])
2
3
# 2. R-read(查询数据)
(1)语法: db.集合名.find(查询条件[, 投影])
举例:查找年龄为18的所有信息
db.students.find({age:18})
举例:查找年龄为18且名字为jack的学生
db.students.find({age:18,name:'jack'})
(2)常用操作符:
< , <= , > , >= , !==
对应为:$lt $lte $gt $gte $ne
举例:年龄是大于等于20的
```mongodb
db.集合名.find({age:{$gte:20}})
```
- 逻辑或:使用
$in
或$or
举例:查找年龄为18或20的学生
```mongodb
db.students.find({age:{$in:[18,20]}})
db.students.find({$or:[{age:18},{age:20}]})
```
- 逻辑非:
$nin
- 正则匹配:
举例:`db.students.find({name:/^T/})`
$where
能写函数:
```mongodb
db.students.find({$where:function(){
return this.name === 'zhangsan' && this.age === 18
}})
```
(3)投影:过滤掉不想要的数据,只保留想要展示的数据 举例:过滤掉 id 和 name
db.students.find({},{_id:0,name:0})
举例:只保留 age
db.students.find({},{age:1})
(4)补充:默认只要找到一个
db.集合名.findOne(查询条件[,投影])
# 3. U-update(更新数据)
语法:
db.集合名.update(查询条件,要更新的内容[,配置对象])
如下写法会将更新内容替换掉整个文档对象,但 _id
不受影响
db.students.update({name:'zhangsan'},{age:19})
使用 $set
修改指定内容,其他数据不变,不过只能匹配一个 zhangsan
db.students.update({name:'zhangsan'},{$set:{age:19}})
修改多个文档对象,匹配多个 zhangsan,把所有 zhangsan 的年龄都替换为 19
db.students.update({name:'zhangsan'},{$set:{age:19}},{multi:true})
补充:
db.集合名.updateOne(查询条件,要更新的内容[,配置对象])
db.集合名.updateMany(查询条件,要更新的内容[,配置对象])
2
# 4. D-delete(删除数据)
语法:
db.集合名.remove(查询条件)
删除所有年龄小于等于19的学生
db.students.remove({age:{$lte:19}})
[!TIP] 学过关系型数据库的写 MongoDB 原生怎删改查确实很难受,于是有了 Nodejs 模块:Mongoose。
# 4. Mongoose 的使用
# 4.1 简介
Mongoose是一个对象文档模型(ODM)库,它对Node原生的MongoDB模块进行了进一步的优化封装,并提供了更多的功能。
# 4.2 优势
- 可以为文档创建一个模式结构(Schema)
- 可以对模型中的对象/文档进行验证
- 数据可以通过类型转换转换为对象模型
- 可以使用中间件来应用业务逻辑挂钩
- 比 Node 原生的 MongoDB 驱动更容易
# 4.3 核心对象(概念)
- Schema
模式对象,通过Schema
可以对集合进行 约束。 - Model
模型对象,相当于数据库中的集合,通过该对象可以 对集合进行操作。 3。 Document
文档对象,它和数据库中的文档相对应,通过它可以读取文档的信息,也可以对文档进行各种操作。
# 4.4 Mongoose 的使用
首先通过 npm
或 yarn
下载安装 Mongoose。
npm i mongoose --save
# 1. 连接数据库
语法:
// 1. 引入 Mongoose
let mongoose = require("mongoose")
// 2. 连接数据库
mongoose.connect("mongodb://[ip地址]:[端口号]/[数据库名]")
2
3
4
举例:
let mongoose = require("mongoose")
mongoose.connect('mongodb://localhost:27017/demo', {
useNewUrlParser: true, // 使用新解析器,解决一些安全性问题
useUnifiedTopology: true // 使用一个统一的拓扑结构
})
2
3
4
5
# 2. 绑定数据库连接的监听
语法:
mongoose.connection.on('open', (err) => {
if (err) {
console.log('数据库连接失败', err)
} else {
console.log('数据库连接成功')
// 进行下一步操作
}
})
2
3
4
5
6
7
8
# 3. 创建核心对象
进行下一步操作:
- 创建
Schema
对象,内部传入约束对象
// 引入 Schema 约束对象
var Schema = mongoose.Schema;
var xxxSchema = new Schema({
字段:类型,
字段:类型,
字段:类型,
字段:类型
});
2
3
4
5
6
7
8
- 生成某个集合所对应的 Model 模型对象
var xxxModel = mongoose.model("集合名",xxxSchema);
- 进行 CRUD 增删改查操作
实例:
// 引入 mongoose
let mongoose = require('mongoose')
// 1. 连接数据库
mongoose.connect('mongodb://localhost:27017/demo', {
useNewUrlParser: true, // 使用新解析器,解决一些安全性问题
useUnifiedTopology: true // 使用一个统一的拓扑结构
})
// 2. 绑定数据库连接的监听
mongoose.connection.on('open', (err) => {
if (err) {
console.log('数据库连接失败', err)
} else {
console.log('数据库连接成功')
// 1. 引入模式对象
let Schema = mongoose.Schema
// 2. 创建约束对象
let studentSchema = new Schema({})
// 3. 生成某个集合所对应的模型对象
let stuModel = mongoose.model('students', studentSchema)
// 4. 进行增删改查
stuModel.create({},(err, data)=>{})
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 4.5 Mongoose 的 CRUD 增删改查
- Create
模型对象.create(文档对象,回调函数)
模型对象.create(文档对象)
2
- Read
模型对象.find(查询条件[,投影])不管有没有数据,都返回一个数组
模型对象.findOne(查询条件[,投影])找到了返回一个对象,没找到返回null
2
- Update
模型对象.updateOne(查询条件,要更新的内容[,配置对象])
模型对象.updateMany(查询条件,要更新的内容[,配置对象])
2
备注:存在 update
方法,但是即将废弃,查询条件匹配到多个时,依然只修改一个,强烈建议用 updateOne
或 updateMany
- Delete
模型对象.deleteOne(查询条件)
模型对象.deleteMany(查询条件)
2
备注:没有 delete
方法,会报错!
Mongoose 增删改查案例:
(1)新增操作
stuModel.create({
stu_id: '004',
name: '静静',
age: 16,
sex: '女',
hobby: ['看番', '听音乐', '喝奶茶'],
info: '温柔的女生'
}, function (err, data) {
// err:错误对象,data:写入的数据
if (!err) {
console.log(data)
} else {
console.log(err)
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(2)查询操作:
// find 方法,返回数组(即使是一条数据),查询结果为空,则返回 []
stuModel.find({ name: '静静1' }, function (err, data) {
if (!err) {
console.log(data)
} else {
console.log(err)
}
})
// findOne 方法,若有结果,则返回一个对象,没有则返回 null
stuModel.findOne({ name: '静静1' }, function (err, data) {
if (!err) {
console.log(data)
} else {
console.log(err)
}
})
// 投影
stuModel.findOne({ name: '瑞秋' }, { age: 1, _id: 0 }, function (err, data) {
if (!err) {
console.log(data)
} else {
console.log(err)
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(3)更新操作:
stuModel.updateOne({ name: '静静' }, { age: 14 }, (err, data) => {
if (!err) {
console.log(data)
} else {
console.log(err)
}
})
2
3
4
5
6
7
(4)删除操作:
stuModel.deleteMany({ age: 22 }, (err, data) => {
if (!err) {
console.log(data)
} else {
console.log(err)
}
})
2
3
4
5
6
7
# 4.6 Mongoose 的模块化编码
直接按照上述方法依次执行,代码都写在一个文件中,代码不好维护管理,使用模块化解决。
- 数据库连接模块
该模块连接数据库,判断连接状态。
db/db.js
文件内容:
let mongoose = require('mongoose')
// 暴露模块,返回一个 Promise 对象
module.exports = new Promise((resolve, reject) => {
// 1. 连接数据库
mongoose.connect('mongodb://localhost:27017/demo', {
useNewUrlParser: true, // 使用新解析器,解决一些安全性问题
useUnifiedTopology: true // 使用一个统一的拓扑结构
})
// 2. 绑定数据库连接的监听
mongoose.connection.on('open', (err) => {
if (err) reject(err)
resolve('数据库连接成功!')
})
})
2
3
4
5
6
7
8
9
10
11
12
13
14
- Mongoose 关键对象模块
该模块用于提供模型对象,需要哪个模型对象就新建一个,例如
teacherModel.js
。module/studentModel.js
文件内容:
let mongoose = require('mongoose')
// (1)引入模式对象
let Schema = mongoose.Schema
// (2)创建约束对象
let studentSchema = new Schema({})
// (3) 生成某个集合所对应的模型对象
module.exports = mongoose.model('students', studentSchema)
2
3
4
5
6
7
8
9
10
- 入口文件:
app.js
// 1. 引入数据库连接模块
let p = require('./db/db')
// 2. 引入学生模型对象
let stuModel = require('./module/studentModel')
// 3. 判断数据库连接状态,成功则进行CRUD
// 异步操作,使用 Promise 封装
p.then((value) => {
console.log(value)
// !CRUD
return new Promise((resolve, reject) => {
stuModel.create({
// 相关数据插入
}, function (err, data) {
// err:错误对象,data:写入的数据
if (err) reject(err)
resolve(data)
})
})
}, (reason) => {
console.log('数据库连接失败!', reason)
}).then((value) => {
console.log('数据添加成功!', value)
}, (reason) => {
console.log('数据添加错误!', reason)
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25