1、NoSql简介
不同于传统的关系型数据库的数据库管理系统
分类
列存储(HBase)
文档存储(MongoDB)
Key-value(Redis)
优势

2、MongoDB简介


3、基本操作
安装
https://www.runoob.com/mongodb/mongodb-osx-install.html
创建日志及数据库存放目录
数据存放路径:
sudo mkdir -p /usr/local/var/mongodb
日志文件路径:
sudo mkdir -p /usr/local/var/log/mongodb
启动MongoDB服务
# 进入mongodb安装目录cd /usr/local/mongodb/bin# 启动mongodb./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 开启认证

查看 mongod 服务是否启动
ps aux | grep -v grep | grep mongod
使用以上命令如果看到有 mongod 的记录表示运行成功。
连接 MongoDB
cd /usr/local/mongodb/bin./mongo

我们启动服务时开启了,auth,所以此时执行show dbs没有权限,也就没有数据。
用户管理
#使用admin数据库use admin#查看有所有数据库show dbs ## => 我们启动服务时开启了,auth,所以此时执行show dbs没有权限,也就没有数据
超级管理员用户
创建一个名为 admin,密码为 123456 的用户。
use admindb.createUser({user:"admin",pwd:"123456",roles:["root"]}) // admin这个数据库是系统自带的数据库,他的用户可以访问任何其他数据库的数据,也叫做超级管理员# 尝试使用上面创建的用户信息进行连接。db.auth('admin', '123456') //=> 通过超级管理员验证 => 1 表示验证通过 0表示验证失败show dbs# ====> 认证之后就有数据了。admin 0.000GBattendees 0.000GBconfig 0.000GBlocal 0.000GB

通过认证之后之后再去执行 show dbs,就可以返回数据了。
创建普通用户(某个数据库的用户)
use admin //=>进入admin数据库db.auth("admin","password") //=> 通过超级管理员验证use blogdb.createUser({user: "blog", pwd: "password", roles: [{ role: "dbOwner", db: "blog" }]})show dbs => admin 0.000GB blog 0.000GB config 0.000GB local 0.000GB
这里我们要注意一点,给创建普通数据库用户的时候要是在超级管理员验证完之后创建。
查看账户
查看全局所有账户
通过超级管理员验证之后
db.system.users.find().pretty()
当前库下的账户
show users
关闭服务
use admin;db.adminCommand({ "shutdown" : 1 })
4、云数据库
MongoDB Atlas
https://cloud.mongodb.com/v2/5d1dfca49ccf640ee938f51e#clusters

5、数据库操作
数据库连接
Node.js环境
const mongoose = require('mongoose');/******************* 数据库连接 Start******************/// 数据库配置const dataBase = config.dataBase;// 数据库连接字符串const dbStr = `${dataBase.pre}${dataBase.user}:${dataBase.pwd}@${dataBase.url}/${dataBase.name}`;spinner.start(chalk.blue(`MongoDB connected start!\n`));// 连接MongoDB数据库mongoose.connect(dbStr, {useNewUrlParser: true, useUnifiedTopology: true});mongoose.connection.on('connected', function (e) {spinner.stop();console.log(chalk.green(`MongoDB connected success~ `));});mongoose.connection.on('error', function () {spinner.stop();console.log(chalk.red(`MongoDB connected fail!`));});mongoose.connection.on('disconnected', function () {spinner.stop();console.log(chalk.red(`MongoDB connected disconnected!`));});/******************* 数据库连接 End* ***************/
6、Schema设计

/***@description: 用户Schema*@author: forguo*@date: 2021/3/24*/const mongoose = require('mongoose');const { Schema, model } = mongoose;const UserSchema = new Schema({userName: {type: String,required: true},userPwd: {type: String,required: true,select: false // 默认不返回},gender: {type: String,required: false}});module.exports = model('User', UserSchema);
7、Mongoose实现增删改查
/***@description: usersController*@author: forguo*@date: 2021/3/20*/const { v4: uuidV4 } = require('uuid');const User = require('../models/users');class Controller {// 查找所有async find(ctx) {ctx.body = await User.find();}// 更新async findByIdAndUpdate(ctx) {ctx.verifyParams({userName: {type: 'string',required: true,},userPwd: {type: 'string',required: true,},});let user = ctx.request.body;let res = await User.findByIdAndUpdate(ctx.params.id, user);if (!res) {ctx.throw(404, '该用户不存在')} else {ctx.body = user;}}// 创建async create(ctx) {ctx.verifyParams({userName: {type: 'string',required: true,},userPwd: {type: 'string',required: true,},});let user = ctx.request.body;user = {userId: `${uuidV4()}`,...user,}ctx.body = await new User(user).save();}// 查询特定async findOne(ctx) {let res = await User.findById(ctx.params.id);if (!res) {ctx.throw(404, '该用户不存在')} else {ctx.body = res;}}// 删除某一个async remove(ctx) {let res = await User.findByIdAndRemove(ctx.params.id);if (!res) {ctx.throw(404, '该用户不存在')} else {ctx.status = 204;}}}module.exports = new Controller();
8、数据库联表查询
Schema 设计
// 与会者attendees: {type: [{type: Schema.Types.ObjectId, // 通过ObjectId与Attendee表关联ref: 'Attendee' // 通过ObjectId与Attendee表关联}],select: false}
查询
populate(‘attendees locations’)
// .populate('attendees'); 获取与之id对应的详细信息const res = await Activity.findById(ctx.params.id).populate('attendees');
返回结果,为attendees表所对应详情数据
{attendees: [{gender: 'male',_id: 606060abe88776334b50b319,user_mobile: '17690909012',user_name: '测试姓名111'},{gender: 'male',_id: 6060622ce55da633f52fa8ad,user_mobile: '176909090114',user_name: '测试姓名111'},{gender: 'male',_id: 6060628d8b160534304e68a1,user_mobile: '176909090111',user_name: '测试姓名111'}],_id: 605ece41697285055e80969b,title: '活动报名',intro: '活动介绍'}
修改数据
// 查询当前活动与会者信息,只查询对应idconst activity = await Activity.findById(ctx.params.id).select('+attendees');activity.attendees.push(attendee._id);// 更新当前活动报名数据activity.save();
9、分页实现
limit、和skip
// 分页参数let {current = 1,size = 10} = ctx.query;current = Math.max(current * 1, 1) - 1;size = Math.max(size * 1, 10);ctx.body = await Activity.find().limit(size).skip(current * size);
10、模糊搜索
Activity.find({title: new RegExp(ctx.query.q) // 模糊搜索})
