2021-11-30

13-1 本章主要内容

使用 MongoDB

  • 之前一直使用 mysql 数据库
  • MongoDB 也是 Nodejs 常用数据库
  • 两者有何区别?该怎么应用?

不要被误导!

  • MongoDB 和 MySQL 是不同的数据库,有不同的使用场景
  • 并不是 MongoDB 适合 nodejs,而 mysql 不适合 nodejs
  • 网上很多用 MongoDB,完全是因为 MongoDB 使用简单

本章内容

  • MongoDB 介绍
  • MongoDB 安装和启动
  • MongoDB 的基本使用
  • MongoDB 重要概念
  • nodejs 连接 MongoDB
  • Mongoose 项目重构

13-2 MongoDB 是文档数据库

MongoDB 介绍

  • MongoDB 是一个文档数据库
  • MongoDB 和 MySQL Redis 的对比
  • 如何选择?举例说明

文档数据库

  • mysql 以表格形式存储数据
  • Redis 以 key/value 形式来存储数据
  • MongoDB 以文档形式存储数据,格式像 JSON

image.png

表格 vs 文档

  • 先不用管 mysql 和 MongoDB,后面再讨论
  • 先思考一下,哪些适合用表格,哪些适合用文档?
  • 即,哪些适合用 Excel写,哪些适合用 Word 写
    • Excel适合存储格式规整的信息,如员工打卡记录,工资表
    • Word适合存储格式松散的信息,如需求文档、宣传方案

MongoDB 对比 MySQL redis

  • mysql - 关系型,表格存储,SQL操作,硬盘
  • Redis - 非关系型,key-value 存储,NoSQL,内存
  • MongoDB - 非关系型,文档存储,NoSQL,硬盘

image.png

  • Excel 可类比 MySQL,Word 可类比 MongoDB
  • MySQL 适合存储格式规整的信息
  • MongoDB 适合存储格式松散的信息,两者可以同时使用

两者结合使用的例子

image.png
网页信息是非常不规整的,所以网页内容可以存储到 MongoDB 中去

博客项目 - 和搜索爬虫类似

  • 用户表,适合用 MySQL 存储
  • 博客记录,适合用 MySQL 存储
  • 博客的内容,适合用MongoDB 存储

2021-12-1

13-3 MongoDB安装 - 介绍

MongoDB 安装

  • 安装 MongoDB 服务端 (Windows 和 mac)
  • 安装 MongoDB 客户端 (Windows 和 mac)
  • 启动和连接

13-4 安装MongoDB-mac-安装homebrew

mac 安装 MongoDB

  • 安装 homebrew
  • 用 homebrew 安装 MongoDB
  • 安装客户端 compass

1.安装 homebrew https://brew.sh/index_zh-cn
2.切换源
https://www.jianshu.com/p/bea984d27cd2

13-5 安装MongoDB-mac-安装MongoDB

在 github 中搜索 mongodb/homebrew-brew
https://github.com/mongodb/homebrew-brew
安装社区版本(MongoDB 不开源)
先切换为独立版本
brew tap mongodb/brew
brew install mongodb-community
慢慢下吧
下好了

类似
https://www.jianshu.com/p/97ae53b089f5

13-6 安装MongoDB-mac-安装Compass

https://www.mongodb.com/try/download/compass
下载
然后在启动台里面找到 compass 启动
然后进入,在启动好 MongoDB 的情况下点击 connect 连接 compass
image.png
image.png

13-10 用 compass 操作 mongodb

MongoDB 使用

  • 创建一个数据库(database)
  • 创建集合(collection)
  • 文档(document)的增删改查

为了更好的管理文档

  • MongoDB 是一个文档数据库,以文档存储信息
  • 但文档也不能散着,否则多了不好管理
  • 分三层管理:数据库->集合->文档

和 MySQL 对比

  • MongoDB 数据库 - MySQL数据库
  • MongoDB 集合 - MySQL 表
  • MongoDB 文档 - MySQL记录(一行数据)

使用 compass 来演示

点左下方的 + 号 创建数据库
然后创建两个 collection :users 和 blogs
然后在 users 这个 collection 中创建一条数据(点击 add data)
image.png
可以把这个_id 想象为一个主键,保证数据的唯一性

2021-12-2

13-11 用命令行操作mongodb

命令行操作

在一些没有桌面的系统必须要用控制台来操作,控制台必学

  • 展示数据库:show dbs
  • 新建: use myblog1
  • 进入:依然是 use ,
  • 展示集合:show collections
  • 向某个集合中插入数据:
    • db.blogs.insert({“title”: “标题1”, “content”: “内容1”, “author”: “zhangsan”})
    • db 表示当前的数据库,然后通过 点 来调用
    • 返回:WriteResult({ “nInserted” : 1 }) 说明成功插入一个文档
  • 查询文档:
    • db.blogs.find()
    • find中可以加查询条件
    • 对查找的内容进行排序
      • db.blogs.find().sort({ _id: -1 })
      • 对 _id 进行倒序排序
  • 更新文档:
    • db.blogs.update(更新条件-更新哪个,更新后的内容)
    • db.blogs.update({“author”: “zhangsan”},{$set: {“title”: “标题A”}})
  • 删除文档:
    • db.blogs.remove()
    • remove 中加条件

总结

  • 数据库(database)创建集合(collection)文档(document)
  • 使用 compass 操作
  • 使用命令行操作

13-12 mongodb的几个重要概念

MongoDB 概念

  • 数据库
  • 集合
  • 文档
  • bson
  • NoSQL

数据库database

  • MongoDB 可以成为数据库系统(服务)
    • 服务层级的,不是功能层级的
  • 一个数据库系统,允许对接很多服务
  • 每个服务,就对接一个(或多个)数据库

image.png

集合 collection

  • 数据库是一个服务(业务)的数据容器
  • 一个服务(业务)的数据,要分类管理
  • 如博客系统,有博客数据,有用户数据

image.png

文档 document

  • 集合 collection 也是一个数据容器
    • 相对数据库而言
  • 文档 document 是单条数据,如一条博客,一个用户
  • 可以被增删改查

image.png

bson

  • JSON 是一种常用的数据格式
  • JSON 是字符串类型的
  • BSON = Binary JSON 即二进制类型的JSON

因此 MongoDB 不是用 JSON 来存储的,而是用类似于 JSON 的 BSON 来存储的

NoSQL

  • 关系型数据库(如 mysql)需要学习 SQL 语言
  • 如 select content
  • NoSQL 数据库则无需用 SQL 语句进行查询,易学易用

13-13 nodejs连接mongodb-part1

连接

  • 安装 MongoDB npm 插件
  • 连接数据库,连接集合
  • 操作文档,CRUD

新建一个 mongodb-test
然后 npm init -y
安装 MongoDB 这个依赖 npm i mongodb
然后新建如下目录和文件
image.png

  1. const MongoClient = require('mongodb').MongoClient
  2. // 设置地址
  3. const url = 'mongodb://localhost:27017'
  4. // 数据库的名字
  5. const dbName = 'myblog'
  6. MongoClient.connect(
  7. url,
  8. {
  9. // 配置
  10. },
  11. (err, client) => {
  12. if (err) {
  13. console.error('mongodb connect error', err)
  14. return
  15. }
  16. // 没有报错,说明连接成功
  17. console.log('mongodb connect success')
  18. // 切换到数据库 (use myblog)
  19. const db = client.db(dbName)
  20. // 关闭连接
  21. // 正式项目不关连接
  22. client.close()
  23. }
  24. )

image.png
成功

2021-12-3

13-14 nodejs操作mongodb-part2

操作增删改查

查询

中间因为是异步,所以需要把关闭连接放到异步回调里

  1. // 切换到数据库 (use myblog)
  2. const db = client.db(dbName)
  3. // 数据库 -> 集合(blogs users) -> 文档
  4. // 使用集合
  5. const usersCollection = db.collection('users')
  6. // 查询数据
  7. usersCollection.find().toArray((err, result) => {
  8. if (err) {
  9. console.error('users find error', err)
  10. return
  11. }
  12. console.log(result)
  13. // 关闭连接
  14. // 正式项目不关连接
  15. client.close()
  16. })

image.png

新增

  1. // 新增数据
  2. usersCollection.insertOne({
  3. username: 'demonlb',
  4. password: 'abc',
  5. realname: '肉饼'
  6. }, (err, result) => {
  7. if (err) {
  8. console.error('users insert error', err)
  9. return
  10. }
  11. console.log(result)
  12. client.close()
  13. })

image.png

修改

        // 修改数据
        usersCollection.updateOne(
            { username: 'lisi' },  // 查询条件
            { $set: { realname: '李四' } }, // 修改内容,注意有 $set
            (err, result) => {
                if (err) {
                    console.error('users update error', err)
                    return
                }
                console.log(result)
                client.close()
            }
        )

image.png

删除

        // 删除数据
        usersCollection.deleteOne(
            {a: 101},
            (err, result => {
                if (err) {
                    console.error('users delete error', err)
                    return
                }

                console.log(result === 'undefined')
                client.close()
            })
        )

如果返回 undefined 代表删除成功
image.png

总结

  • 安装 mongodb npm 插件
  • 连接数据库,连接集合
  • 操作数据库,CRUD

2021-12-4

13-15 使用mongoose连接mongodb服务

mongoose

在 MongoDB 的层级之上

  • Schema 和 Model(规范和模型)
  • 基于 Model 操作数据
  • 使用 MongoDB 重构项目

MongoDB 数据格式过于灵活

  • 可以插入任何格式数据,不受限制
  • 实际项目开发时,要有数据格式的规范(重要)
  • 特别是多人协作开发时

那不就和 MySQL 一样了吗?

  • 这仅仅是使用层面的调整,并不是MongoDB 的初衷
  • 如果数据格式以松散数据为主,少量格式规范的数据,可以这么用(mongoose)
  • 如果大量数据都是规范数据,最好直接选择 MySQL

mongoose 可提供规范

  • Schema 定义数据格式的规范
  • 以 Model 规范 collection
  • 规范数据操作 API

实操

安装 mongoose
npm i mongoose —save
然后新建 mongoose 文件夹进行测试
连接一下

const mongoose = require('mongoose')

const url = 'mongodb://localhost:27017'
const dbName = 'myblog'

mongoose.connect(`${url}/${dbName}`, {
    // 配置信息
})

// 获取连接对象
const db = mongoose.connection

// 处理连接错误报错
db.on('error', err => {
    console.error(err)
})

// 连接成功 open 状态
db.once('open', () => {
    console.log('mongoose connect success')
})

module.exports = mongoose

image.png

13-16 mongoose的Schema和Model

新建一个 models 的文件夹
然后再依次新建两个文件 Blog.js 和 User.js
image.png
然后写规范和model

// 对应 blogs 的那个 collection

const mongoose = require('../connect')

// 用 Schema 定义数据规范
// 和 collection 里面数据一一对应,key: type
const BlogSchema = mongoose.Schema({
    title: {
        type: String,
        required: true, // 必需
    },
    content: String,
    author: {
        type: String,
        required: true, // 必需
    },
})

// Model 对应 collection 
// 这里把 collection 名字特地写成单数形式,mongoose 会在对应时自动将其变为复数形式
const Blog = mongoose.model('blog', BlogSchema)

module.exports = Blog

类似的

// 对应 users 的那个 collection

const mongoose = require('../connect')

// 用 Schema 定义数据规范
// 和 collection 里面数据一一对应,key: type
const UserSchema = mongoose.Schema({
    username: {
        type: String,
        required: true, // 必需
        unique: true // 唯一,不能重复
    },
    password: String,
    realname: String
})

// Model 对应 collection 
// 这里把 collection 名字特地写成单数形式,mongoose 会在对应时自动将其变为复数形式
const User = mongoose.model('user', UserSchema)

module.exports = User

2021-12-5

13-18 mongoose操作mongodb

操作用户表

image.png

const User = require('../models/User')

// 自执行的异步函数

!(async () => {

    // 创建用户
    const zhangsan = await User.create({
        username: 'zhangsan',
        password: '123',
        realname: '张三'
    })
    console.log('zhangsan', zhangsan)
})()

插入成功!
image.png
然后查询

    // 查询
    const list = await User.find()
    console.log(list)

image.png

操作博客表

类似的

const Blog = require('../models/Blog')

// 自执行的异步函数

!(async () => {

    // 新建博客
    const blogCreate = await Blog.create({
        title: 'mongoose标题',
        content: 'mongoose内容',
        author: 'demonlb'
    })

    console.log('blogCreate', blogCreate)

})()

image.png
全部

const Blog = require('../models/Blog')

// 自执行的异步函数

!(async () => {

    // 新建博客
    const blogCreate = await Blog.create({
        title: 'mongoose标题',
        content: 'mongoose内容',
        author: 'demonlb'
    })

    console.log('blogCreate', blogCreate)

    // 获取列表,按照 id 逆序排列
    const list = await Blog.find().sort({ _id: -1 })
    console.log('list', list) // 数组形式
    // 模糊查询 /标题/ /A/

    // 根据 id 获取博客内容获取的是对象形式的内容
    const blogGetById = await Blog.findById('61ac1d62ea6da95064e180c9')
    console.log('blogGetById', blogGetById)

    // 修改博客
    const blogUpdate = await Blog.findOneAndUpdate(
        { _id: '61ac1d62ea6da95064e180c9' },
        { content: 'mongoose 修改后的内容' },
        {
            new: true // 返回修改后的内容,默认为 false,即返回修改前的内容
        }
    )
    console.log('blogUpdate', blogUpdate)

    // 删除博客
    const blogDelete = await Blog.findOneAndDelete({
        _id: '61ac1d62ea6da95064e180c9',
        author: 'demonlb' // 验证一下作者,增加安全性,防止误删
    })
    console.log('blogDelete', blogDelete)
})()

13-19 博客项目web-server链接mongodb服务端

使用 mongodb 重构项目

  • 回顾现有代码(基于 koa2 编写的)
  • 定义 Schema 和 Model
  • 完善数据操作

先把之前使用 mysql-koa2 的项目内容复制到新创建的 blog-koa2-mongodb ,然后重构
首先安装 mongoose

然后复制 models 文件夹和 db.js 到 db文件夹中,
然后给 models 里的 Schema 加一个时间戳 (timestamps)
image.png
然后下一步就开始改 controller 代码

13-20 博客项目web-server使用mognodb数据库

修改 controller-user.js

首先修改 controller/user.js

const User = require('../db/models/User')
const { genPassword } = require('../utils/crypt')

const login = async (username, password) =>{
    // 生成加密密码
    password = genPassword(password)

    const userList = await User.find({
        username,
        password
    })

    if (userList.length === 0) return {}
    return userList[0]
}

module.exports = {
    login
}

更新加密密码

因为这里的密码是加密过的,所以要将数据库中的密码也修改成加密过的
新建一个 password_test.js 然后把 genPassword 引入进来 将数据库里的账号和密码都进行解析,变成加密过的
依次更新一下
image.png
image.png

修改 controller-blog.js

类似的

const xss = require('xss')
const Blog = require('../db/models/Blog')

const getList = async (author, keyword) => {

    // 动态拼接查询条件
    const whereOpt = {}
    if (author) whereOpt.author = author
    // 兼容模糊查询
    if (keyword) whereOpt.keyword = new RegExp(keyword)

    const list = await Blog.find(whereOpt).sort({ _id: -1 })

    return list
}

const getDetail = async (id) => {
    const blog = await Blog.findById(id)

    // 创建时间格式化

    return blog
}

const newBlog = async (blogData = {}) => {
    // blogData 是一个博客对象,包含 title content author属性

    const title = xss(blogData.title)
    const content = xss(blogData.content) 
    const author = blogData.author

    const blog = await Blog.create({
        title,
        content,
        author
    })

    return {
        id: blog._id
    }
}

const updateBlog = async (id, blogData = {}) => {
    // blogData 是一个博客对象,包含 title content 属性

    // 更新时只需要更新blogData的 title content 属性

    const title = xss(blogData.title)
    const content = xss(blogData.content)

    const blog = await Blog.findOneAndUpdate(
        { _id: id },
        { content, title },
        { new: true}
    )

    if (blog == null) return false
    return true
}

const deleteBlog = async (id, author) => {
    // id 就是要删除博客的id

    const blog = await Blog.findOneAndDelete(
        { id: _id, author },
    )

    if (blog == null) return false
    return true
}

module.exports = {
    getList,
    getDetail,
    newBlog,
    updateBlog,
    deleteBlog
}

2021-12-5

13-21 博客项目web-server使用mongodb-联调和测试

然后 npm run dev 启动一下项目
测试一下,没什么问题

13-22 本章总结

本章主要是把项目切换到 MongoDB 的数据库,也就说是项目的第三次重构
本章内容

  • MongoDB 介绍
  • MongoDB 的安装和启动-Windows Mac
  • MongoDB 的基本使用-compass terminal
  • MongoDB 的重要概念-数据库, 集合,文档,bson,NoSQL
  • nodejs 连接 MongoDB
  • mongoose 项目重构 - Schema model