MongoDB 简介
MongoDB 是一个基于分布式文件存储的数据库(DataBase),官方网站是www.mongodb.com。
-
数据库(DataBase)
- 数据库本质上就是应用程序,也就是软件
- 它按照数据结构来组织、存储和管理数据
- 主要作用就是管理数据 ,对数据进行 增(c)、删(d)、改(u)、查(r)操作
-
使用 Ajax 操作 JSON 文件也可以对数据进行管理,为何还要使用数据库?
-
数据库管理数据的特点
相比于纯文件管理数据,数据库管理数据很多优势
-
速度更快
在数据库软件内部存在一些特定的数据结构,可以提高数据的访问速度 数据库一般都会借助内存来缓存数据内容,内存也叫临时存储器,读取速度是永久存储器(也就是硬盘)的 N 倍,所以速度会更快
-
扩展性更强
比如现在有一个项目,项目的数据是放在数据库中的,在这个项目运行了一段时间之后,发现用户比较大、数据量比较大,此时可以创建多个数据库的节点,从而减小单个数据库节点的压力,并且保证整个数据库的正常运作
-
安全性更高
大多数数据库都会对数据进行加密处理,并且还会添加身份校验、权限管理等各种功能,进一步保证数据的安全性,所以我们在网站所能看到的所有数据其实都是存放在数据库当中的
-
-
-
MongoDB 数据库与其他数据库的区别
- 市场上其实存在很多类型的数据库,如比较知名的 MySQL、SqlServer、Oracle 等等,为何选择 MongoDB 数据库?
- 因为 MongoDB 较其他数据库而言,操作语法与 JavaScript 类似(都是使用对象.方法等语言进行操作),容易上手,学习成本低,可以非常快速的就学会使用数据库软件
- MySQL 等数据库更适合后端语言开发使用,搭配的更加紧密,当然 Node.js 也可以使用
- 数据库学习可以说是一通百通,使用熟练以后,再学其他数据库也会更容易一些
MongoDB 核心概念
Mongodb 中有几个重要概念
-
数据库(DataBase)
- 数据库是一个数据仓库,数据库服务下可以创建很多数据仓库,数据仓库中可以存放很多集合
- 因为在一台网站服务器中可以放置多个网站应用,每个网站应用都需要一个独立的数据仓库,我们只需安装一个数据库软件,就可以在内部建立多个数据仓库
-
集合(collection)
- 集合,就是具有同一类特征的数据组合成的数据集,如用户信息与商品信息存储在不同的集合中
- 在数据仓库内部,可以建立多个集合
- 集合类似于 JS 中的数组,在集合中可以存放很多文档
-
文档(document)
- 文档,就是具体的一条条的数据,在数据库中就是一条条 JSON 格式的对象
- 在集合内部,可以有多个文档
- 文档是数据库中用于存储的最小单位,类似于 JS 中的对象
-
字段(field)
- 字段,就是文档中的属性名
- JSON 格式对象的内部,存在很多属性,数据库中将 JSON 格式对象的属性叫做字段。比如
"name":"张三" "age":18等等,类比 JS 中的对象属性
在数据库软件中可以包含多个数据仓库,在每个数据仓库中可以包含多个数据集合,每个数据集合中可以包含多条文档 (具体的数据),每条文档中可以存在多个字段
类比JSON文件如:
{
"users": [
{
"uname": "zhangsan",
"password": "zs123456",
"id": 1
},
{
"uname": "lisi",
"password": "666",
"email": "dz@166.com",
"id": 2
},
{
"uname": "666",
"password": "666",
"email": "dz@166.com",
"id": 3
}
],
"comments": [
{
"uname": "小郭",
"comment": "我爹是郭巨侠",
"time": "2012-03-15 14:32:35",
"id": 1
},
{
"uname": "jack",
"comment": "十多个三国杀",
"time": "2023-04-21 09:43:24",
"id": 8
},
{
"uname": "张三",
"comment": "王侯将相宁有种乎!",
"time": "2023/05/06 14:34:30",
"id": 9
}
]
}
可以通过类比 JSON 文件来理解一下 MongoDB 中的概念
- 一个 JSON 文件就像一个数据库,MongoDB 服务中可以存在 N 个数据库
- JSON 文件中的接口就像数据库中的一个个集合,每个数据库中可以存在多个集合
- 接口数组中保存的一条条对象类型的数据就好比数据库中的文档,每个文档中可以存在多个字段
- 对象中存放的一个个属性就好比数据库中的字段,每个字段要有指定的类型
一般来说一个项目中只会使用一个数据库;在同一个集合中会存储具有同一类特征的数据
MongoDB 的下载安装
可以在 www.mongodb.com/try/downloa…这个地址中,下载社区版的MongoDB数据库
版本区别(了解)
- alpha - 内测版 - 开发团队内部检测bug使用,不建议使用
- beta - 公测版 - 面向公众的测试版本,可能存在bug,不建议使用
- pre - 先行版 - 与alpha版本类似,不建议使用
- RC(release candidate) - 候选版 - 不建议使用
- release - 发行版 - 官方推荐使用版本,一般不会后面写这个标识
- stable - 稳定版 - 相比其他版本来说bug较少,最为稳定,也是开发中最常使用的版本
- current或lastest - 尝鲜版(最新版) - 可能存在大量的bug,运行时不稳定,不建议使用
下载时,建议使用5.0.17 版本 ,选择zip类型进行下载,使用更加方便
服务器配置
-
将MongoDB压缩版解压到除C盘外的任意目录中
-
在文件解压的那个盘的根目录下,创建data文件夹,然后在data 文件夹中创建db文件夹,如当前将MongoDB解压到了D盘,就要创建
D:/data/db目录,MongoDB会将数据默认保存在这个文件夹 -
以MongoDB文件的bin目录作为工作目录,打开cmd
-
输入
mongod命令,它会自动执行当前文件夹下的mongod.exe文件,这是MongoDB的服务器运行程序看到信息中出现wating for connections... 等信息,就表示数据库服务已经开启成功,下一步就可以使用客户端来链接数据库服务了
一般不要选中数据库服务端窗口中的内容,选中时可能会停止提供服务,一旦选中可以使用回车键取消选中
-
打开一个新的cmd,注意不要关闭之前开启的数据库服务,输入
mongo命令,它会自动执行当前文件夹下的mongo.exe文件,这是MongoDB的客户端运行程序 -
配置环境变量
为了便于以后使用MongoDB命令更方便,我们使用将MongoDB的bin目录配置到环境变量path中
1. 查看电脑属性 找到此电脑右键
2. 进行高级系统设置,查看环境变量
3. 在系统变量中找到path变量并选中,点击编辑
4. 在编辑环境变量中点击新建,填入MongoDB的bin目录的绝对路径,并确定保存即可
MongoDB常用命令(了解)
一般来说,学习数据库都需要使用一些常用的数据库命令,后面学习图形化界面操作以后使用较少,所以了解一些常用的即可
数据库命令
-
显示所有数据库
show dbs -
切换到指定数据库,如果数据库不存在,会自动帮我们创建数据库
use 数据库名 -
显示当前所在数据库
db -
删除当前数据库
use 数据库名 db.dropDatabase()
集合命令
-
创建集合
db.createCollection("集合名") -
显示当前数据库中的所有集合
show collections -
删除某个集合
db.集合名.drop() -
给集合改名
db.集合名.renameCollection("集合的新名字")
文档命令
-
插入文档
db.集合名.insert(文档对象) -
查询文档
db.集合名.find(指定条件) -
更新文档
db.集合名.update(指定条件,新文档)db.集合名.updata({age:18},{$set:{age:36}})更新文档是直接以一个新文档的形式来替换旧文档的,所以如果不使用$set:{}这种形式来替换指定字段的数据,很容易造成其他数据丢失
-
删除文档
db.集合名.remove(指定条件)
_id 是我们MongoDB数据库中自动生成的唯一编码,用来作为文档的唯一标识
应用场景
新增
- 新用户的注册
- 信息发布(发朋友圈、抖音动态等等)
- 内容评论
- 弹幕发送等等
- 添加购物车
- ..........
删除
- 删除购物车
- 删除发布的动态
- 删除评论
- 删除文档等等
- ............
在一些项目中不会真的把指定的数据从数据库中进行删除,而是做了一些伪删除处理(就是不从数据库中真的删除数据,而是在其内部添加一条特定的属性,如
is_deleted:true,当值为true时,在检索时会忽略此数据,说明这项数据已经被做出删除处理,反之(值为false)说明数据正常)优点:通过这种方式可以让历史数据得以保存,如果用户操作不当删除l数据时,可以让其进行数据恢复
更新
- 更新个人信息
- 修改商品价格
- 修改动态
- ...........
查询
查询功能是我们使用最多的,查询在应用程序中无处不在
- 信息列表
- 商品列表
- 动态列表
- 搜索引擎搜索
- ..............
mongoose
mongoose简介
面向node.js来更优雅的创建MongoDB对象模型
使用命令行操作数据库,来完成一个项目中所有与数据相关的功能,显然是不可行的,因为编写MongoDB验证、转换和业务逻辑是非常麻烦的,所以诞生了mongoose。Mongoose 是一个对象文档模型库
mongoose的作用
Mongoose提供了一种直接的、基于文档类型规则模式结构的数据库建模解决方案,而且它还包含数据类型转换、验证,查询构建,业务逻辑钩子等功能,开箱即用。让我们可以在node.js中使用代码操作 mongodb 数据库。
mongoose使用
-
安装 mongoose 模块
npm i mongoose -
导入mongoose模块
const mongoose = require('mongoose') -
使用mongoose模块提供的connect方法,连接指定的数据库
// 参数就是我们要链接的数据库名称 如果这个数据库不存在,它会帮我们自动创建 mongoose.connect("mongodb://127.0.0.1:27017/weibo") -
设置连接回调,进行事件监听
// 让我们可以在连接成功、连接失败、关闭连接等事件发生时,进行一些事件处理 // 监听连接成功事件 mongoose.connection.on("open", () => { console.log("connect the db is ok"); }) // 监听连接失败事件 mongoose.connection.on("error", () => { console.log("open a lots of error"); }) // 监听连接关闭事件 mongoose.connection.on("close", () => { console.log("close the db"); })监听连接成功事件时,也可以使用once方法
mongoose.connection.once("open", () => { console.log("connect the db is ok"); })-
once与on的区别
-
当数据库服务掉线时,mongoose会尝试重新连接,重连成功以后
- 如果使用once,callback不会再重新执行
- 如果使用on,callback会重新执行
-
官方推荐使用once,因为在open事件中一般要写入大量的执行代码
- 如在其中写入了
app.listen(80),这个代码只会执行一次,当多次执行时肯定是无效的,且会报错
- 如在其中写入了
-
使用node运行JavaScript文件时,如果出现关于 { useNewUrlParser: true } 与 { useUnifiedTopology: true } 的警告提示信息,可以根据提示按下列方式处理
-
在connect参数中写入参数
{ useNewUrlParser: true, useUnifiedTopology: true }- seNewUrlParser 使用新的解析器
- useUnifiedTopology 使用新的服务器发现和监控引擎
mongoose.connect("mongodb://127.0.0.1:27017/cilicili", { useNewUrlParser: true, useUnifiedTopology: true })
-
-
当数据库连接成功后,在其回调函数内部创建集合对象,并定义文档结构(属性名、属性值的数据类型等)
// 设定集合规则 const BookSchema = new mongoose.Schema( // 定义文档的数据结构 // 创建文档的属性名及属性值的类型 { name: String, author: String, price: Number, time: Date } ) -
创建文档模型对象(集合)并应用规则
// 创建模型对象 // 让创建的对象使用我们定义好的文档结构规则 const BookModel = mongoose.model("Book", BookSchema) -
创建文档(新增)
-
方法1,创建实例对象
const xiyou = new BookModel( // 参数就是要插入的数据 { name: "西游记", author: "吴承恩", price: 36.8, time: new Date() } // 数据库会自动帮助我们创建一个_id值 // _v是版本值,一般用不到 ) console.log(xiyou); -
方法2,使用异步函数创建
BookModel.create( // 参数就是要插入的数据 { name: "石头记", author: "曹雪芹", price: 26.5, time: new Date() } ) .then(data => { // 操作成功,显示新增的数据 console.log(data); }) .catch(err => { // 操作失败,抛出错误信息 throw err })
-
-
操作数据库成功后,及时关闭连接,减少性能消耗
// 养成操作完数据就关闭连接的好习惯 mongoose.disconnect()
字段类型的说明(了解)
| 类型 | 说明 |
|---|---|
| String | 字符串类型,常用于文本等内容 |
| Number | 数值型,常用于数量、价格、年龄等内容 |
| Boolean | 布尔类型 |
| Array | 数组,也可以使用[ ]来表示,用于一组数据 |
| Date | 日期 |
| Buffer | Buffer对象中存储的是二进制的数据流【可用于存储图片、音频、视频等,但是使用的不多,因为这些资源一般都被存放到静态资源文件夹中,然后将其路径处理为url交给数据库进行保存了,只需使用对应url就能访问到这些资源】 |
| ObjectId | 对象Id,需要使用mongoose.Schema.Types.ObjectId指定数据类型,这个值必须是文档的Id值,一般用来外键使用【外键就是,将另一个文档中的Id存放在此文档中,让另一个文档与当前文档进行关联,当我们需要调用另一个文档中的数据时,可以通过这个Id直接调取,多使用在联合查询中】 |
| Mixed | 任意类型,就是不限制数据类型,需要mongoose.Schema.Types.Mixed指定数据类型 |
| Decimal | 高精度数字,需要使用mongoose.Schema.Types.Decimal128指定数据类型,当数据需要较高数字精度时使用 |
字段验证
在创建集合规则时,可以设置当前字段的验证规则,对新增文档中的属性值进行验证
-
验证成功将让其进入进行存储
-
验证失败就会输出插入失败并拒绝进行存储
-
验证规则
-
required: true 必填字段
-
minlength:3 字符串最小长度为3
-
maxlength: 20 字符串最大长度为20
-
min: 2 数值最小为2
-
max: 100 数值最大为100
-
enum: ['html', 'css', 'javascript', 'node.js'] 枚举值
-
trim: true 去除字符串两边的空格
-
validate: 自定义验证器
-
default: 默认值
-
unique: true 唯一值
- 唯一值需要重新创建集合才会生效
- 用户输入的数据类型用于不可靠
-
-
获取错误信息
error.errors['字段名称'].message
数据库常用操作
常用操作无非是增(create)删(delete)改(update)查(find)
新增
-
添加单条文档
文档模型对象.create(文档).then(处理新增成功的语句).catch(处理添加失败的语句)
BookModel.create( // 参数就是要插入的数据 { name: "石头记", author: "曹雪芹", price: 26.5, time: new Date() } ) .then(data => { // 操作成功,显示新增的数据 console.log(data); // 8. 关闭数据库链接 // 养成操作完数据就关闭连接的好习惯 mongoose.disconnect() }) .catch(err => { // 操作失败,抛出错误信息 throw err }) -
添加多条文档
文档模型对象.inserMany([文档]).then(处理新增成功的语句).catch(处理添加失败的语句)
BookModel.insertMany( [ { name: "葫芦娃", author: "小金刚", price: 29.8, time: new Date(), is_hot: true, type: ["传说"], language: "英语" }, { name: "三毛流浪记", author: "失名", price: 29.8, time: new Date(), is_hot: true, type: ["历史"], language: "英语" } ] ).then(data => { console.log(data); console.log(1); }) .catch(err => { throw err })
删除
-
删除单条文档
文档模型对象.deleteOne(指定的唯一条件).then(处理成功的语句).catch(处理失败的语句)
BookModel.deleteOne({ _id: "645b5c955280cf50e895e21e" }) .then(() => { console.log("删除成功"); }) .catch(() => { console.log("删除失败"); }) -
删除多条文档
文档模型对象.deleteMany(指定条件).then(处理成功的语句).catch(处理失败的语句)
BookModel.deleteMany({ name: "三国演义1998" }) .then(() => { console.log("删除成功"); }) .catch(() => { console.log("删除失败"); })
更新
-
更新单条文档
文档模型对象.updateOne(指定的唯一条件).then(处理成功的语句).catch(处理失败的语句)
BookModel.updateOne({ _id: "645b515f5aabc42dbcbdf138" }, { name: "国家分裂为3股势力斗争的爱恨情仇" }) .then(() => { console.log("更新成功"); }) .catch(() => { console.log("更新失败"); }) -
更新多条文档
文档模型对象.updateMany(指定条件).then(处理成功的语句).catch(处理失败的语句)
BookModel.updateMany({ author: "罗贯中" }, { price: 9.9 }) .then(() => { console.log("更新成功"); }) .catch(() => { console.log("更新失败"); })
查询
-
查询单条文档
文档模型对象.findOne(指定的唯一条件).then(处理成功的语句).catch(处理添加失败的语句)
BookModel.findOne({ _id: "645b515f5aabc42dbcbdf138" }) .then((data) => { console.log(data); }) .catch(() => { console.log("查询失败"); }) -
通过id查询文档
文档模型对象.findById(Id值).then(处理成功的语句).catch(处理添加失败的语句)
BookModel.findById("645b515f5aabc42dbcbdf138") .then((data) => { console.log(data); }) .catch(() => { console.log("查询失败"); }) -
查询所有的文档
文档模型对象.find().then(处理成功的语句).catch(处理添加失败的语句)
// 如果参数为空,会查询所有的数据 BookModel.find() .then((data) => { console.log(data); }) .catch(() => { console.log("查询失败"); }) -
查询多条文档
文档模型对象.find().then(指定条件).catch(处理添加失败的语句)
// 如果写入参数,参数为指定的条件
BookModel.find({ name: "三国演义" })
.then((data) => {
console.log(data);
})
.catch(() => {
console.log("查询失败");
})