【Node进阶之路】八. MongoDB

122 阅读6分钟

1700202822518.png

1. 简介

1-1. Mongodb 是什么

MongoDB 是一个基于分布式文件存储的数据库,官方地址 www.mongodb.com/

1-2. 数据库是什么

数据库(DataBase)是按照数据结构来组织、存储和管理数据的 应用程序

1-3. 数据库的作用

数据库的主要作用就是 管理数据 ,对数据进行 增(c)删(d)改(u)查(r)

1-4. 数据库管理数据的特点

相比于纯文件管理数据,数据库管理数据有如下特点:

  1. 速度更快
  2. 扩展性更强
  3. 安全性更强

1-5. 为什么选择 Mongodb

操作语法与 JavaScript 类似,容易上手,学习成本低

2. 核心概念

Mongodb 中有三个重要概念需要掌握

  • 数据库(database) 数据库是一个数据仓库,数据库服务下可以创建很多数据库,数据库中可以存 放很多集合
  • 集合(collection) 集合类似于 JS 中的数组,在集合中可以存放很多文档
  • 文档(document) 文档是数据库中的最小单位,类似于 JS 中的对象

1700203448756.png

JSON 文件示例:

{
    "accounts": [
        {
        "id": "3-YLju5f3",
        "title": "买电脑",
        "time": "2023-02-08",
        "type": "-1",
        "account": "5500",
        "remarks": "为了上网课"
        },
        {
        "id": "3-YLju5f4",
        "title": "请女朋友吃饭",
        "time": "2023-02-08",
        "type": "-1",
        "account": "214",
        "remarks": "情人节聚餐"
        },
        {
        "id": "mRQiD4s3K",
        "title": "发工资",
        "time": "2023-02-19",
        "type": "1",
        "account": "4396",
        "remarks": "终于发工资啦!~~"
        }
    ],
    "users":[
        {
        "id": 1,
        "name": "zhangsan",
        "age": 18
        },
        {
        "id": 2,
        "name": "lisi",
        "age": 20
        },
        {
        "id": 3,
        "name": "wangwu",
        "age": 22
        }
    ]
}

大家可以通过 JSON 文件来理解 Mongodb 中的概念:

  • 一个 JSON 文件 好比是一个 数据库 ,一个 Mongodb 服务下可以有 N 个数据库
  • JSON 文件中的 一级属性的数组值 好比是 集合
  • 数组中的对象好比是 文档
  • 对象中的属性有时也称之为 字段

一般情况下:

  • 一个项目使用一个数据库
  • 一个集合会存储同一种类型的数据

3. 下载安装与启动

下载地址: www.mongodb.com/try/downloa…

建议选择 zip 类型, 通用性更强

配置步骤如下:

  1. 将压缩包移动到 C:\Program Files 下,然后解压

  2. 创建 C:\data\db 目录,mongodb 会将数据默认保存在这个文件夹

  3. 以 mongodb 中 bin 目录作为工作目录,启动命令行

  4. 运行命令 mongod

1700205010442.png

看到最后的 waiting for connections 则表明服务 已经启动成功

然后可以使用 mongo 命令连接本机的 mongodb 服务

1700205059497.png

注意:

  • 为了方便后续方便使用 mongod 命令,可以将 bin 目录配置到环境变量 Path 中
  • 千万不要选中服务端窗口的内容 ,选中会停止服务,可以 敲回车 取消选中

4. 命令行交互

命令行交互一般是学习数据库的第一步,不过这些命令在后续用的比较少,所以大家了解即可

4-1. 数据库命令

  1. 显示所有的数据库

    show dbs
    
  2. 切换到指定的数据库,如果数据库不存在会自动创建数据库

    use 数据库名
    
  3. 显示当前所在的数据库

    db
    
  4. 删除当前数据库

    use 库名
    db.dropDatabase()
    

4-2. 集合命令

  1. 创建集合

    db.createCollection('集合名称')
    
  2. 显示当前数据库中的所有集合

    show collections
    
  3. 删除某个集合

    db.集合名.drop()
    
  4. 重命名集合

    db.集合名.renameCollection('newName')
    

4-3. 文档命令

  1. 插入文档

    db.集合名.insert(文档对象);
    
  2. 查询文档

    db.集合名.find(查询条件)
    

    _id 是 mongodb 自动生成的唯一编号,用来唯一标识文档

  3. 更新文档

    db.集合名.update(查询条件,新的文档)
    db.集合名.update({name:'张三'},{$set:{age:19}})
    
  4. 删除文档

    db.集合名.remove(查询条件)
    

4-4. 应用场景

4-4-1. 新增
  • 用户注册
  • 发布视频
  • 发布商品
  • 发朋友圈
  • 发评论
  • 发微博
  • 发弹幕
  • ······
4-4-5. 删除
  • 删除评论
  • 删除商品
  • 删除文章
  • 删除视频
  • 删除微博
  • ······
4-4-6. 更新
  • 更新个人信息
  • 修改商品价格
  • 修改文章内容
  • ······
4-4-7. 查询
  • 商品列表
  • 视频列表
  • 朋友圈列表
  • 微博列表
  • 搜索功能
  • ······

5. Mongoose

5-1. 介绍

Mongoose 是一个对象文档模型库,官网 www.mongoosejs.net/

5-2. 作用

方便使用代码操作 mongodb 数据库

5-3. 使用流程

//1. 安装 mongoose
//2. 导入 mongoose
const mongoose = require('mongoose');
//3. 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/bilibili');
//4. 设置连接回调
//连接成功
mongoose.connection.on('open', () => {
    console.log('连接成功');
    //5. 创建文档结构对象
    let BookSchema = new mongoose.Schema({
        title: String,
        author: String,
        price: Number
    });
    //6. 创建文档模型对象
    let BookModel = mongoose.model('books', BookSchema);
    //7. 插入文档
     let book = {
        name:'西游记',
        author:'吴承恩',
        price:39.9
    }
    // BookModel.create(book,(err,data) => {  // 旧版的写法,新版本已经不再支持回调函数,需用promise的写法
    //     // 判断是否有错误
    //     if(err) {
    //         console.log(err);
    //         return
    //     }
    //     // 如果没有出错,则输出插入后的文档对象
    //     console.log(data);
    // })
    BookModel.create(book).then((data) => {
        console.log(data);
    }).catch(err => {
        console.log(err);
    }) 
});
//连接出错
mongoose.connection.on('error', () => {
		console.log('连接出错~~');
})
//连接关闭
mongoose.connection.on('close', () => {
		console.log('连接关闭');
})

5-4. 字段类型

文档结构可选的常用字段类型列表

类型描述
String字符串
Number数字
Boolean布尔值
Array数组,也可以使用 [] 来标识
Date日期
BufferBuffer 对象
Mixed任意类型,需要使用 mongoose.Schema.Types.Mixed 指定
ObjectId对象 ID,需要使用 mongoose.Schema.Types.ObjectId 指定
Decimal128高精度数字,需要使用 mongoose.Schema.Types.Decimal128 指定

5-5. 字段值验证

Mongoose 有一些内建验证器,可以对字段值进行验证

5-5-1. 必填项
title: {
  type: String,
  required: true // 设置必填项
},
5-5-2. 默认值
author: {
  type: String,
  default: '匿名' //默认值
},
5-5-3. 枚举值
gender: {
  type: String,
  enum: ['男','女'] //设置的值必须是数组中的
},
5-5-4. 唯一值
username: {
    type: String,
    unique: true
},

unique 需要 重建集合 才能有效果 永远不要相信用户的输入

5-6. CURD

数据库的基本操作包括四个,增加(create),删除(delete),修改(update),查(read)

5-6-1. 增加

插入一条数据

let book = {
    name: '水浒传',
    author: '施耐庵',
    price: 59.9,
    des: '这是一段描述~',
    style: '志怪'
 }
 /**第一种写法(已弃用) */
// BookModel.create(book,(err,data) => {
//     // 判断是否有错误
//     if(err) {
//         console.log(err);
//         return
//     }
//     // 如果没有出错,则输出插入后的文档对象
//     console.log(data);
// })
/**第二种写法 */
// BookModel.create(book).then((data) => {
//     console.log(data);
//     //8. 断开连接
//     mongoose.disconnect();  
// }).catch(err => {
//     console.log(err);
// }) 
    /**第三种写法(推荐) */
  try {
      const data = await BookModel.create(book);
      console.log('插入成功--', data);
      //8. 断开连接
      mongoose.disconnect();
  } catch (error) {
      console.log('插入失败--', error);
  }   

批量插入

// 1.安装mongoose

// 2.导入
const mongoose = require('mongoose');

// 3.连接 mongodb 服务                      数据库名称
mongoose.connect('mongodb://127.0.0.1:27017/bilibili');

// 4.设置回调
// 设置连接成功的回调
mongoose.connection.once('open', async () => {
    // 5.创建文档结构对象
    // 设置集合中文档的属性和属性值的类型
    let BookSchema = new mongoose.Schema({
        name: {
            type: String,
            unique: true
        },
        author: String,
        price: Number,        
        style: {
            type: String,
            enum: ['言情', '城市', '志怪','侠义','战争']
        }
    })
    // 6.创建模型对象
    let BookModel = mongoose.model('levels', BookSchema);

    // 7.新增
    let books = [{
        name: '水浒传',
        author: '施耐庵',
        price: 39.9,        
        style: '侠义'
    },{
      	name: '西游记',
        author: '吴承恩',
        price: 59.9,        
        style: '志怪'
    },{
      	name: '红楼梦',
        author: '曹雪芹',
        price: 19.9,        
        style: '言情'
    },{
      	name: '三国演义',
        author: '罗贯中',
        price: 29.9,        
        style: '战争'
    }]  
    /**第三种写法 */
    try {
        const data = await BookModel.insertMany(books);
        console.log('插入成功--', data);
        //8. 断开连接
        mongoose.disconnect();
    } catch (error) {
        console.log('插入失败--', error);
    }

});

// 设置连接错误的回调
mongoose.connection.on('error', () => {
    console.log('连接失败');
});

// 设置连接关闭的回调
mongoose.connection.on('close', () => {
    console.log('连接关闭');
});

// 关闭mongodb的连接
// setTimeout(() => {
//     mongoose.disconnect();
// }, 2000);
5-6-2. 删除

删除一条数据

SongModel.deleteOne({_id:'5dd65f32be6401035cb5b1ed'}).then(() => {
  console.log('删除成功');
  mongoose.connection.close();
}).catch(err => {
  console.log('删除失败');
});

批量删除

SongModel.deleteMany({author:'Jay'}).then(() => {
  console.log('删除成功');
	mongoose.connection.close();
}).catch(err => {
  console.log('删除失败');
});
5-6-3. 更新

更新一条数据

SongModel.updateOne({name: '红楼梦'},{price:9.9}).then(() => {
  console.log('更新成功');
  mongoose.connection.close();
}).catch(err => {
  console.log('更新失败');
});

批量更新数据

SongModel.updateMany({author: '余华'}, {is_hot: true}).then(() => {
  console.log('更新成功');
  	mongoose.connection.close();
}).catch(err => {
  console.log('更新失败');
});
5-6-4. 查询

查询一条数据

SongModel.findOne({name: '红楼梦'}).then(data => {
  	console.log(data);
		mongoose.connection.close();
}).catch(err => {
  throw err;
});
//根据 id 查询数据
SongModel.findById('5dd662b5381fc316b44ce167').then((data) => {
  	console.log(data);
		mongoose.connection.close();
}).catch((err) => {
  	console.log('查询失败');
});

批量查询数据

//不加条件查询
SongModel.find().then((data) => {
  console.log(data);
  mongoose.connection.close();
}).catch(err => {
  	console.log('查询失败');  
})
//加条件查询
SongModel.find({author: '余华'}).then(data => {
  console.log(data);
  mongoose.connection.close();
}).catch(err => {
  	console.log('查询失败');   
});

5-7. 条件控制

5-7-1. 运算符

在 mongodb 不能 > < >= <= !== 等运算符,需要使用替代符号

  • > 使用 $gt
  • < 使用 $lt
  • >= 使用 $gte
  • <= 使用 lte
  • !== 使用 $ne
db.students.find({id:{$gt:3}});  //id号比3大的所有的记录
5-7-2. 逻辑运算

$or 逻辑或的情况

db.students.find({$or:[{age:18},{age:24}]});

$and 逻辑与的情况

db.students.find({$and: [{age: {$lt:20}}, {age: {$gt: 15}}]});
5-7-3. 正则匹配

条件中可以直接使用 JS 的正则语法,通过正则可以进行模糊查询

db.students.find({name:/imissyou/});
// 如果是匹配一个变量,可使用以下写法
let str = 'imissyou'
db.students.find({name: new RegExp(str)});

5-8. 个性化读取

5-8-1. 字段筛选
//0:不要的字段
//1:要的字段
SongModel.find().select({_id:0,title:1}).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
5-8-2. 数据排序
//sort 排序
//1:升序
//-1:倒序
SongModel.find().sort({hot:1}).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});
5-8-3. 数据截取
//skip 跳过 limit 限定
SongModel.find().skip(10).limit(10).exec(function(err,data){
if(err) throw err;
console.log(data);
mongoose.connection.close();
});

5-9. Mongoose代码模块化

代码模块化的目的是为了更好的维护代码,减少代码量,避免重复的逻辑书写代码。

  1. 首先根目录新建 db文件夹,新建 db/db.js 文件,在此文件封装连接Mongodb数据库的相关操作。

    /**
     * @param {*} success  数据库连接成功的回调
     * @param {*} error 数据库连接失败的回调
     */
    module.exports = function (success, error) {    
        // 1.安装mongoose
        // 2.导入
        const mongoose = require('mongoose');
        // 导入配置文件
        const { DBHOST, DBNAME, DBPORT } = require('../config/config');
    
        // 3.连接 mongodb 服务                      数据库名称
        mongoose.connect(`mongodb://127.0.0.1:27017/bilibili`);
    
        // 4.设置回调
        // 设置连接成功的回调
        mongoose.connection.once('open', () => {
            success();
        });
    
        // 设置连接错误的回调
        mongoose.connection.on('error', () => {
            error();
        });
    
        // 设置连接关闭的回调
        mongoose.connection.on('close', () => {
            console.log('连接关闭');
        });
    }
    
    
  2. 根目录index.js中调用

    // 导入db文件
    const db = require('./db/db');
    // 导入mongoose
    const mongoose = require('mongoose');
    
    db(()=> { 
        console.log('连接成功');
    }, () => {
        console.log('连接失败');
    })
    
    
  3. 根目录创建 models文件夹,存放文档模型对象

    bookmodel.js

    // 导入mongoose
    const mongoose = require('mongoose');
    // 创建文档结构对象
    // 设置集合中文档的属性和属性值的类型
    let BookSchema = new mongoose.Schema({
        name: {
            type: String,
            unique: true
        },
        author: String,
        price: Number
    })
    // 创建模型对象
    let BookModel = mongoose.model('books', BookSchema);
    
    // 暴露模型对象
    module.exports = BookModel;
    
  4. index.js文件中引入 bookmodel.js,进行相关数据库操作

    // 导入db文件
    const db = require('./db/db');
    // 导入mongoose
    const mongoose = require('mongoose');
    // 导入bookmodel
    const BookModel = require('./models/bookmodel');
    
    db(async()=> { 
        // 新增
        let book = {
            name: '三国演义',
            author: '罗贯中',
            price: 69.9,        
            style: '战争'
        }     
        // 插入数据
        try {
            const data = await BookModel.create(book);
            console.log('成功--', data);
            //8. 断开连接
            mongoose.disconnect();
        } catch (error) {
            console.log('失败--', error);
        }
    
    }, () => {
        console.log('连接失败');
    })
    
    
    
  5. 优化 db.js

    判断error 为其设置默认值,调用时可不传error函数

    /**
     * @param {*} success  数据库连接成功的回调
     * @param {*} error 数据库连接失败的回调
     */
    module.exports = function (success, error) {
        // 判断error 为其设置默认值
        if (typeof err !== 'function') {
            error = () => {
                console.log('连接失败');
            }
        }
        ······
    }
    

    单独配置数据库连接,新建 config/config.js配置文件

    // 配置文件
    module.exports = {
        DBHOST:'127.0.0.1',
        DBPORT: 27017,
        DBNAME:'bilibili'
    }
    

    db.js 中导入配置文件,将数据库连接设置成变量

    /**
     * @param {*} success  数据库连接成功的回调
     * @param {*} error 数据库连接失败的回调
     */
    module.exports = function (success, error) {
        ······
        
        // 导入配置文件
        const { DBHOST, DBNAME, DBPORT } = require('../config/config');
    
        // 3.连接 mongodb 服务                      数据库名称
        mongoose.connect(`mongodb://${DBHOST}:${DBPORT}/${DBNAME}`);
    		
    		······
    }
    

    优化后的 db.js

    /**
     * @param {*} success  数据库连接成功的回调
     * @param {*} error 数据库连接失败的回调
     */
    module.exports = function (success, error) {
        // 判断error 为其设置默认值
        if (typeof err !== 'function') {
            error = () => {
                console.log('连接失败');
            }
        }
        // 1.安装mongoose
        // 2.导入
        const mongoose = require('mongoose');
        // 导入配置文件
        const { DBHOST, DBNAME, DBPORT } = require('../config/config');
    
        // 3.连接 mongodb 服务                      数据库名称
        mongoose.connect(`mongodb://${DBHOST}:${DBPORT}/${DBNAME}`);
    
        // 4.设置回调
        // 设置连接成功的回调
        mongoose.connection.once('open', () => {
            success();
        });
    
        // 设置连接错误的回调
        mongoose.connection.on('error', () => {
            error();
        });
    
        // 设置连接关闭的回调
        mongoose.connection.on('close', () => {
            console.log('连接关闭');
        });
    }
    

6. 图形化管理工具

我们可以使用图形化的管理工具来对 Mongodb 进行交互,这里演示两个图形化工具