1 Web架构
web总共分为三个部分:
- 客户端
- 服务器
- 数据库
web网站访问过程:
- 客户端向服务器发送请求
- 服务器操作数据库
- 数据库将结果返回给服务器
- 服务器将结果响应给客户端
2 数据库概念
数据库(Database)
- 数据库是按照数据结构来组织、存储和管理数据的仓库
- 程序在内存中运行,一旦程序运行结束或者计算机断电,程序运行中的数据都会丢失
- 因此我们需要将一些程序运行的数据保存到硬盘当中,而数据库就是数据持久化的最佳选择
- 简而言之,数据库就是存储数据的仓库
数据库分类
数据库主要分为两种:
- 关系型数据库(RDBMS)
- MySQL、Oracle、DB2、SQL Server
- 关系数据库中都是数据表
- 非关系型数据库(NoSQL - Not Only SQL)
- SQL结构化查询语言
- 所有关系型数据库都是使用SQL操作
- 标准化语言,是一门语言
- 比如W3C规范,是一种标准,由各个厂商实现
- 每个厂商实现方式不完全一样
- 标准化虽然可以带来开发和学习成本的简化,但是同时限制了创新的机会
- MongoDB、Redis
- 文档数据库MongoDB
- 键值对数据库
- SQL结构化查询语言
3 MongoDB 简介
- MongoDB是为快速开发互联网Web应用设计的数据库系统
- MongoDB设计目标是极简、灵活、作为Web应用栈的一部分
- MongoDB的数据模型是面向文档的,文档是一种类似于JSON的结构
- 简单来说就是MongoDB数据库存储的是各种各样的JSON
- 增强版的JSON,叫做BSON,可以存储二进制数据,可以认为就是JSON
4 安装MongoDB
下载安装
下载地址:https://www.mongodb.com/try/download/community
- 偶数版为稳定版,奇数版为开发版
- 对32位系统支持不好,不建议使用32位系统安装
- 从官网下载MongoDB数据库安装包至本地,双击该安装包,根据安装提示一步一步操作,完成数据库的安装。
配置环境变量
- 我的电脑 -> 右键属性 -> 高级系统设置 -> 环境变量 -> 系统环境变量 -> 找到 Path
- 双击Path -> 在弹窗内添加mongodb安装目录
D:\Project\MongoDB\Server\5.0\bin
-> 点击所有确定保存 - win + R 键打开控制台 -> 输入
mongod
-> 没有出现不是内部或外部命令说明可以使用了
5 开启MongoDB服务
- 在命令行工具中运行命令
mongo
,连接 mongodb,出现>
说明启动成功 - 默认监听
27017
端口 - 默认端口不要修改,需要修改的话,最大不能超过
65535
数据库(database)
- 数据库服务器
- 服务器用来保存数据
- 最新版本默认已启动
- 数据库客户端
- 客户端用来操作服务器,对数据进行增删改查的操作
6 基本概念
数据库服务器里面可以有多个数据库。
- 数据库(database)
- 数据库是一个仓库,在仓库中可以存放多个集合
- 集合(collection)
- 集合类似于数组,在集合中可以存放多个文档
- 文档(document)
- 数据库中的最小单位,存储和操作的内容都是文档
- 字段
- 文档中的一条数据,属性名就是字段名
- 数据库和集合都不需要手动创建
- 当我们创建文档时,如果文档所在的集合或数据库不存在会自动创建
7 安装可视化工具
下载地址:https://www.mongodbmanager.com/download-mongodb-manager-free
8 基本操作
常用命令
- 显示数据库
show dbs
、show databases
- 进入数据库
use test
- 操作数据库
db
代表当前数据库
- 显示数据集合
show collections
CRUD (增删改查) 操作
- 数据库中插入一个或多个文档
db.<集合名>.insert(doc)
db.<集合名>.insertOne(doc)
插入一个文档db.<集合名>.insertMany(doc)
插入多个文档- 下面两个方法更像是第一个方法的拆分,但是下面两个语义更加清晰
- 插入文档时,如果没有给文档指定 _id 属性,则数据库会自动为文档添加 _id,可以自己指定 _id
- 该属性为文档的唯一标识,不可重复,根据时间戳+机器码生成
ObjectId()
,确保数据唯一
// 向 test 数据库中 person 集合插入一个新数据 {name:"张三",age:"18"}
db.person.insert({name:"张三", age:"18"});
// 多条数据
db.person.insert([{name:"张三", age:"18"},{name:"李四", age:"18"},{name:"赵五", age:"18"}
]);
- 查询集合中所有符合条件的文档
db.<集合名>.find({})
可以接受一个对象作为条件参数{属性名1:值,属性名2:值}
查询属性是指定值的文档db.<集合名>.findOne({})
用来查询集合中符合条件的第一个文档db.<集合名>.find({}).count()
查询所有结果的数量
- 修改集合中符合条件的文档
db.<集合名>.update({查询条件},{新对象},{配置})
默认只修改一个db.<集合名>.updateOne({查询条件},{新对象})
修改一个符合条件的文档db.<集合名>.updateMany({查询条件},{新对象})
同时修改多个符合条件的文档db.<集合名>.replaceOne({查询条件},{新对象})
替换一个符合条件的文档- 默认使用新对象替换旧对象
- 如果需要修改指定的属性,而不是替换,需要使用“修改操作符”来完成修改
$set
可以修改文档中的指定属性$unset
可以用来删除文档的指定属性
db.person.update({name:"张三"},{$set: {sex: "男",address: "幸福村"}
});// 修改多个
db.person.update({name:"张三"},{$set: {sex: "男",address: "幸福村"}},{multi: true}
);db.person.update({name:"张三"},{$unset: {address: "111"}
});
- 删除集合中符合条件的文档
db.<集合名>.remove({条件})
- 删除符合条件的所有文档,第二个参数为 true 只删除一个
- 条件必须设置,如果没有直接删除所有文档
db.<集合名>.deleteOne({条件})
删除符合条件的一个文档db.<集合名>.deleteMany({条件})
删除符合条件的多个文档db.<集合名>.drop()
删除集合db.dropDatabase()
删除数据库
- 数据库中数据一般不会真正的删除,所以删除的方法很少调用
- 一般都是单独添加一个字段,表示数据是否删除
- 这种删除只是程序上的删除,不是物理删除
- 不建议使用物理删除,因为删除之后无法找回
- 文档的属性值可以是一个文档,当一个文档的属性值是一个文档时,我们称这个文档叫做内嵌文档
其他方法
skip((页码-1)*每页显示条数).limit(显示条数)
limit()
用于设置显示数据的上限skip()
用于跳过指定数量的数据sort()
需要传递一个对象指定排序规则,1 为升序,-1 为降序db.user.find({}).sort({_id:1,name:-1})
db.user.find({},{name:1,_id:0})
$gt
大于$gte
大于等于$lt
小于$lte
小于等于
9 练习作业
- 进入 user_manage 数据库
- 向数据库中的 users 集合中插入文档
- 文档的内容包含用户名、密码、年龄、爱好、邮箱、是否删除
10 文档关系
- 一对一(one to one)
- 夫妻(一个丈夫对应一个妻子)
- 可以使用内嵌文档的方式体现
- 一对多(one to many)/ 多对一(many to one)
- 用户 - 银行卡
- 用户 - 订单
- 可以通过内嵌文档的方式体现
- 通过单个字段实现关联
- 多对多(many to many)
- 分类 - 商品
- 老师 - 学生
- 添加字段值为数组
11 插件操作数据库
- 大部分使用程序来完成数据库操作
- Mongoose 让我们可以通过 Node 操作 MongoDB 模板
- Mongoose 是对象文档模型(ODM)库,对原生的模块进行了封装,提供了更多的功能
Mongoose 优势
官方地址:http://www.mongoosejs.net/
- 可以为文档创建一个模式结构(Schema)
- 可以对模型中的对象/文档进行验证
- 数据可以通过类型转换转换为对象
- 可以使用中间件来应用业务逻辑挂钩
- 比 Node 原生的 MongoDB 驱动更容易
使用 Mongoose
- 使用
npm install mongoose
命令下载 - 使用
const mongoose = require('mongoose');
引入 mongoose - 使用
mongoose.connect('mongodb://localhost/user_manage');
- 如果使用默认端口号(27017),可以省略不写
- 监听 MongoDB 数据库的连接状态
- mongoose 对象中有一个 connection 属性,表示数据库连接
- 通过监视该对象,可以来监听数据库的连接与断开
mongoose.connection.once('open',function(){})
数据库连接成功事件mongoose.connection.once('close',function(){})
数据库连接断开事件
- 使用
mongoose.disconnect()
断开数据库连接(一般不使用)- 一般只需要连接一次,连接一次以后,除非停止服务器,否则连接不会断开
Mongoose 对象
- Schema(模式对象)
- 定义约束了数据库中的文档结构
- Model
- Model 对象作为集合中的所有文档表示
- 相当于 MongoDB数据库中的集合collection
- Document
- 表示集合中的具体文档
Schema 对象
const Schema = mongoose.Schema;
// 创建 Schema(模式)对象
let stuSchema = new Schema({name: String,age: Number,sex: {type: String,default: '男'},address: String
});
// 通过 Schema 来创建 Model
// Model 代表的是数据库中的集合,通过 Model 才能对数据库进行操作
// mongoose.model(modelName, Schema);
// modelName 是要映射的集合名
// mongoose 会自动将集合名变成复数
let StuModel = mongoose.model('student', stuSchema);// 向数据库中插入一个文档
// StuModel.create(doc, function(err){});
StuModel.create({name: '孙悟空',age: 18,sex: '男',address: '花果山'
}, function(err){if(!err){console.log('插入成功');}
});
Model 方法
Model.create(doc(s), [callback])
创建一个或多个文档并添加到数据库中doc(s)
可以是一个文档对象,也可以是一个对象数组callback
操作完成以后调用的回调函数
StuModel.create({name: '孙悟空',age: 18,sex: '男',address: '花果山'
}, function(err){if(!err){console.log('插入成功');}
});
Model.find(conditions, [projection], [options], [callback])
查询所有符合条件的文档Model.findById(id, [projection], [options], [callback])
根据文档id属性查询文档Model.findOne([conditions], [projection], [options], [callback])
查询符合条件的第一个文档conditions
查询条件projection
投影 需要获取的字段- 两种方式
{name: 1, _id: 0}
"name age -_id"
options
查询选项(skip
limit
)callback
回调函数。查询结果结果会通过回调函数返回,参数必选,不传没有返回值- 通过
find()
查询的结果,返回的对象就是 Document,文档对象 - Document 对象是 Model 的实例
doc instanceof StuModel
- 通过
StuModel.find({ name: '孙悟空' }, { name: 1, _id: 0 }, { skip: 2, limint: 10 }, function (err, docs) {if (!err) {console.log(docs);}
});
Model.update(conditions, doc, [options], [callback])
Model.updateMany(conditions, doc, [options], [callback])
Model.updateOne(conditions, doc, [options], [callback])
- 修改一个或多个文档
conditions
查询条件doc
修改后的对象options
配置参数callback
回调函数
Model.replaceOne(conditions, doc, [options], [callback])
StuModel.updateOne({ name: '张三' }, { $set: { age: 20 } }, function (err) {if (!err) {console.log('修改成功');}
});
Model.remove(conditions, [callback])
Model.deleteOne(conditions, [callback])
Model.deleteMany(conditions, [callback])
- 删除一个或多个文档
conditions
查询条件callback
回调函数
StuModel.remove({ name: '张三' }, function (err) {if (!err) {console.log('删除成功');}
});
Model.count(conditions, [callback])
- 统计文档的数量
Model.count({ name: '张三' }, function (err, count) {if (!err) {console.log(count);}
});
Document 对象
- Document 和集合中的文档一一对应,Document 是 Model 的实例
- 通过 Model 查询到的结果都是 Document
Model#save([options], [fn])
保存文档对象
// 创建一个Document
let stu = new StuModel({name: '孙悟空',age: 18,sex: '男',address: '花果山'
});// Document 方法
stu.save(function(err){if(!err){console.log('插入成功');}
});StuModel.findOne({}, function (err, doc) {if (!err) {console.log(doc);// 修改方式1doc.update({$set:{age:20}},function(err){if(!err){console.log('修改成功');}})// 修改方式2doc.age = 20;doc.save();// 删除doc.remove(function(err){if(!err){console.log('删除成功');}});// 获取属性值console.log(doc.get('age'));console.log(doc.age);// 设置属性值doc.set('name', '张小三');doc.name = '张小三';// 获取 _id 值doc._id}
});
模块化连接
- 定义一个模块连接数据库
// tools/conn_mongo.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/user_manage');
mongoose.connection.once('open', function () {console.log('数据库连接成功');
})// index.js
require('./tools/conn_mongo');
- 定义一个模块,操作 Student 模型
// models/student.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const stuSchema = new Schema({name: String,age: Number,sex: {type: String,default: '男'},address: String
});
// 定义模型
const StuModel = mongoose.model('student', stuSchema);
module.exports = StuModel;// index.js
let stu = require('./models/student');
stu.find({}, function(err, docs){if(!err){console.log(docs);}
})