1、NoSql简介

不同于传统的关系型数据库的数据库管理系统

分类

列存储(HBase)
文档存储(MongoDB)
Key-value(Redis)

优势

image.png

2、MongoDB简介

image.png

image.png

3、基本操作

安装

https://www.runoob.com/mongodb/mongodb-osx-install.html

创建日志及数据库存放目录

  • 数据存放路径:

    1. sudo mkdir -p /usr/local/var/mongodb
  • 日志文件路径:

    1. sudo mkdir -p /usr/local/var/log/mongodb

启动MongoDB服务

  1. # 进入mongodb安装目录
  2. cd /usr/local/mongodb/bin
  3. # 启动mongodb
  4. ./mongod --port 27017 --auth --dbpath /usr/local/var/mongodb --logpath /usr/local/var/log/mongodb/mongo.log --logappend --fork
  • —dbpath 设置数据存放目录
  • —logpath 设置日志存放目录
  • —fork 在后台运行
  • —port 运行端口
  • —mongodb 错误日志采用追加模式,mongodb的日志会追加到现有的日志文件,而不是从新创建一个新文件 **logappend=true**
  • —auth 开启认证

image.png

查看 mongod 服务是否启动

  1. ps aux | grep -v grep | grep mongod

image.png

使用以上命令如果看到有 mongod 的记录表示运行成功。

连接 MongoDB

  1. cd /usr/local/mongodb/bin
  2. ./mongo

image.png
我们启动服务时开启了,auth,所以此时执行show dbs没有权限,也就没有数据。

用户管理

  1. #使用admin数据库
  2. use admin
  3. #查看有所有数据库
  4. show dbs ## => 我们启动服务时开启了,auth,所以此时执行show dbs没有权限,也就没有数据

超级管理员用户

创建一个名为 admin,密码为 123456 的用户。

  1. use admin
  2. db.createUser({user:"admin",pwd:"123456",roles:["root"]}) // admin这个数据库是系统自带的数据库,他的用户可以访问任何其他数据库的数据,也叫做超级管理员
  3. # 尝试使用上面创建的用户信息进行连接。
  4. db.auth('admin', '123456') //=> 通过超级管理员验证 => 1 表示验证通过 0表示验证失败
  5. show dbs
  6. # ====> 认证之后就有数据了。
  7. admin 0.000GB
  8. attendees 0.000GB
  9. config 0.000GB
  10. local 0.000GB

image.png
通过认证之后之后再去执行 show dbs,就可以返回数据了。

创建普通用户(某个数据库的用户)

  1. use admin //=>进入admin数据库
  2. db.auth("admin","password") //=> 通过超级管理员验证
  3. use blog
  4. db.createUser({user: "blog", pwd: "password", roles: [{ role: "dbOwner", db: "blog" }]})
  5. show dbs => admin 0.000GB blog 0.000GB config 0.000GB local 0.000GB

这里我们要注意一点,给创建普通数据库用户的时候要是在超级管理员验证完之后创建。

查看账户

查看全局所有账户

通过超级管理员验证之后

  1. db.system.users.find().pretty()

当前库下的账户
  1. show users

关闭服务

  1. use admin;
  2. db.adminCommand({ "shutdown" : 1 })

4、云数据库

MongoDB Atlas

https://cloud.mongodb.com/v2/5d1dfca49ccf640ee938f51e#clusters

image.png

5、数据库操作

数据库连接

Node.js环境

  1. const mongoose = require('mongoose');
  2. /******************
  3. * 数据库连接 Start
  4. ******************/
  5. // 数据库配置
  6. const dataBase = config.dataBase;
  7. // 数据库连接字符串
  8. const dbStr = `${dataBase.pre}${dataBase.user}:${dataBase.pwd}@${dataBase.url}/${dataBase.name}`;
  9. spinner.start(chalk.blue(`MongoDB connected start!\n`));
  10. // 连接MongoDB数据库
  11. mongoose.connect(dbStr, {useNewUrlParser: true, useUnifiedTopology: true});
  12. mongoose.connection.on('connected', function (e) {
  13. spinner.stop();
  14. console.log(chalk.green(`MongoDB connected success~ `));
  15. });
  16. mongoose.connection.on('error', function () {
  17. spinner.stop();
  18. console.log(chalk.red(`MongoDB connected fail!`));
  19. });
  20. mongoose.connection.on('disconnected', function () {
  21. spinner.stop();
  22. console.log(chalk.red(`MongoDB connected disconnected!`));
  23. });
  24. /******************
  25. * 数据库连接 End
  26. * ***************/

6、Schema设计

image.png

  1. /**
  2. *@description: 用户Schema
  3. *@author: forguo
  4. *@date: 2021/3/24
  5. */
  6. const mongoose = require('mongoose');
  7. const { Schema, model } = mongoose;
  8. const UserSchema = new Schema({
  9. userName: {
  10. type: String,
  11. required: true
  12. },
  13. userPwd: {
  14. type: String,
  15. required: true,
  16. select: false // 默认不返回
  17. },
  18. gender: {
  19. type: String,
  20. required: false
  21. }
  22. });
  23. module.exports = model('User', UserSchema);

7、Mongoose实现增删改查

  1. /**
  2. *@description: usersController
  3. *@author: forguo
  4. *@date: 2021/3/20
  5. */
  6. const { v4: uuidV4 } = require('uuid');
  7. const User = require('../models/users');
  8. class Controller {
  9. // 查找所有
  10. async find(ctx) {
  11. ctx.body = await User.find();
  12. }
  13. // 更新
  14. async findByIdAndUpdate(ctx) {
  15. ctx.verifyParams({
  16. userName: {
  17. type: 'string',
  18. required: true,
  19. },
  20. userPwd: {
  21. type: 'string',
  22. required: true,
  23. },
  24. });
  25. let user = ctx.request.body;
  26. let res = await User.findByIdAndUpdate(ctx.params.id, user);
  27. if (!res) {
  28. ctx.throw(404, '该用户不存在')
  29. } else {
  30. ctx.body = user;
  31. }
  32. }
  33. // 创建
  34. async create(ctx) {
  35. ctx.verifyParams({
  36. userName: {
  37. type: 'string',
  38. required: true,
  39. },
  40. userPwd: {
  41. type: 'string',
  42. required: true,
  43. },
  44. });
  45. let user = ctx.request.body;
  46. user = {
  47. userId: `${uuidV4()}`,
  48. ...user,
  49. }
  50. ctx.body = await new User(user).save();
  51. }
  52. // 查询特定
  53. async findOne(ctx) {
  54. let res = await User.findById(ctx.params.id);
  55. if (!res) {
  56. ctx.throw(404, '该用户不存在')
  57. } else {
  58. ctx.body = res;
  59. }
  60. }
  61. // 删除某一个
  62. async remove(ctx) {
  63. let res = await User.findByIdAndRemove(ctx.params.id);
  64. if (!res) {
  65. ctx.throw(404, '该用户不存在')
  66. } else {
  67. ctx.status = 204;
  68. }
  69. }
  70. }
  71. module.exports = new Controller();

8、数据库联表查询

Schema 设计

  1. // 与会者
  2. attendees: {
  3. type: [
  4. {
  5. type: Schema.Types.ObjectId, // 通过ObjectId与Attendee表关联
  6. ref: 'Attendee' // 通过ObjectId与Attendee表关联
  7. }
  8. ],
  9. select: false
  10. }

查询

populate(‘attendees locations’)

  1. // .populate('attendees'); 获取与之id对应的详细信息
  2. const res = await Activity.findById(ctx.params.id).populate('attendees');

返回结果,为attendees表所对应详情数据

  1. {
  2. attendees: [
  3. {
  4. gender: 'male',
  5. _id: 606060abe88776334b50b319,
  6. user_mobile: '17690909012',
  7. user_name: '测试姓名111'
  8. },
  9. {
  10. gender: 'male',
  11. _id: 6060622ce55da633f52fa8ad,
  12. user_mobile: '176909090114',
  13. user_name: '测试姓名111'
  14. },
  15. {
  16. gender: 'male',
  17. _id: 6060628d8b160534304e68a1,
  18. user_mobile: '176909090111',
  19. user_name: '测试姓名111'
  20. }
  21. ],
  22. _id: 605ece41697285055e80969b,
  23. title: '活动报名',
  24. intro: '活动介绍'
  25. }

修改数据

  1. // 查询当前活动与会者信息,只查询对应id
  2. const activity = await Activity.findById(ctx.params.id).select('+attendees');
  3. activity.attendees.push(attendee._id);
  4. // 更新当前活动报名数据
  5. activity.save();

9、分页实现

limit、和skip

  1. // 分页参数
  2. let {
  3. current = 1,
  4. size = 10
  5. } = ctx.query;
  6. current = Math.max(current * 1, 1) - 1;
  7. size = Math.max(size * 1, 10);
  8. ctx.body = await Activity.find().limit(size).skip(current * size);

10、模糊搜索

  1. Activity.find({
  2. title: new RegExp(ctx.query.q) // 模糊搜索
  3. })