# MongoDB
# 1. 数据库概述及环境搭建
# 1.1 为什么要使用数据库
- 动态网站中的数据都是存储在数据库中的
- 数据库可以用来持久存储客户端通过表单收集的用户信息
- 数据库软件本身可以对数据进行高效的管理
# 1.2 什么是数据库
- 数据库即存储数据的仓库,可以将数据进行有序的分门别类的存储。它是独立于语言之外的软件,可以通过数据库软件提供的 API 去操作数据。
- 常见的数据库软件有:mysql、mongoDB、oracle。
# 1.3 MongoDB 数据库下载安装
下载地址:https://www.mongodb.com/download-center/community (opens new window)
# 1.4 MongoDB 可视化软件
MongoDB Compass 可视化操作软件,是使用图形界面操作数据库的一种方式。
# 1.5 数据库相关概念
在一个数据库软件中可以包含多个数据仓库,在每个数据仓库中可以包含多个数据集合,每个数据集合中可以包含多条文档(具体的数据)。
术语 | 解释说明 |
---|---|
database | 数据库,mongoDB 数据库软件中可以建立多个数据库 |
collection | 集合,一组数据的集合,可以理解为 JavaScript 中的数组 |
document | 文档,一条具体的数据,可以理解为 JavaScript 中的对象 |
field | 字段,文档中的属性名称,可以理解为 JavaScript 中的对象属性 |
# 1.6 Mongoose 第三方包
使用 Node.js 操作 MongoDB 数据库需要依赖 Node.js 第三方包 mongoose
npm install mongoose -g
# 1.7 启动 MongoDB
在命令行工具中运行下面的命令即可启动 MongoDB,否则 MongoDB 将无法连接。
net start mongodb
# 1.8 数据库连接
使用 mongoose 提供的 connect 方法即可连接数据库。
mongoose
.connect("mongodb://localhost/playground", {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log("数据库连接成功"))
.catch((err) => console.log("数据库连接失败", err));
# 1.9 创建数据库
在 MongoDB 中不需要显式创建数据库,如果正在使用的数据库不存在,MongoDB 会自动创建。
# 2. MongoDB 增删改查操作
# 2.1 创建集合
创建集合分为两步,一是对对集合设定规则,二是创建集合,创建 mongoose. Schema 构造函数的实例即可创建集合。
// 1.创建集合规则
const courseSchema = new mongoose.Schema({
name: String,
author: String,
isPublished: Boolean
});
// 2.创建符合集合规则的构造函数
const Course = mongoose.model("Course", courseSchema); //courses
# 2.2 创建文档(增)
创建文档实际上就是向集合中插入数据。分为两步:
- 应用集合规则创建集合实例。
- 调用实例对象下的 save()方法将数据保存到数据库中。
// 创建集合实例
const course = new Course({
name: "Node.js course",
author: "itheima",
tags: ["node", "backend"],
isPublished: true
});
// 将数据保存到数据库中
course.save();
也可使用集合构造函数本身的 create 方法创建文档
- create(object, callback) 回调函数形式
Course.create(
{
name: "javascript基础",
author: "pink",
isPublished: false
},
(err, result) => {
console.log(err);
console.log(result);
}
);
- create(object).then().catch() promise 对象形式
Course.create({
name: "javascript应用",
author: "pink",
isPublished: true
})
.then((doc) => console.log(doc))
.catch((err) => console.log(err));
# 2.3 mongoDB 数据库导入数据(增)
找到 mongodb 数据库的安装目录,将安装目录下的 bin 目录放置在环境变量中。
$mongoimport –d 数据库名称 –c 集合名称 –file 要导入的数据文件
# 2.4 查询文档(查)
// 根据条件查找文档(条件为空则查找所有文档)
Course.find().then((result) => console.log(result));
// 通过字段查找
Course.findOne({
name: "node.js基础"
}).then((result) => console.log(result));
// 匹配大于 小于
User.find({
age: {
$gt: 20,
$lt: 50
}
}).then((result) => console.log(result));
// 匹配包含
User.find({
hobbies: {
$in: ["敲代码"]
}
}).then((result) => console.log(result));
// 选择要查询的字段
User.find()
.select("name email")
.then((result) => console.log(result));
// 将数据按照年龄进行排序
User.find()
.sort("age")
.then((result) => console.log(result));
// skip 跳过多少条数据 limit 限制查询数量
User.find()
.skip(2)
.limit(2)
.then((result) => console.log(result));
# 2.5 删除文档(删)
// 删除单个
Course.findOneAndDelete({
_id: "5c09f267aeb04b22f8460968"
}).then((result) => console.log(result));
// 删除多个
User.deleteMany({}).then((result) => console.log(result));
# 2.6 更新文档(改)
// 更新单个
User.updateOne(
{
查询条件
},
{
要修改的值
}
).then((result) => console.log(result));
// 更新多个
User.updateMany(
{
查询条件
},
{
要更改的值
}
).then((result) => console.log(result));
# 2.7 规则验证
在创建集合规则时,可以设置当前字段的验证规则,验证失败就则输入插入失败。
required: true 必传字段
minlength: 3 字符串最小长度
maxlength: 20 字符串最大长度
min: 2 数值最小为2
max: 100 数值最大为100
enum: ['html', 'css', 'javascript', 'node.js']
trim: true 去除字符串两边的空格
validate: 自定义验证器
default: 默认值
//定义集合规则
const postSchema = new mongoose.Schema({
// 定义验证规则
title: {
type: String,
// 此字段是否必须,必须
required: [true, "\n请传入文章标题"],
minlength: [2, "\n文章长度不能小于2"],
maxlength: [5, "\n文章长度不能超过5"],
// 去除字符串两边的空格
trim: true
},
age: {
type: Number,
min: 18,
max: 100
},
publishData: {
type: Date,
// 默认值
default: Date.now
},
categories: -{
type: String,
// 枚举,列出当前字段可以拥有的值
enum: {
values: ["html", "css", "javascript", "node.js"],
message: "\n传入的分类名称在列表中不存在"
}
},
author: {
type: String,
// 自定义规则
validate: {
validator: (v) => {
// 返回布尔值
return v && v.length > 4;
},
// 自定义错误信息
message: "\n传入的值不符合验证规则"
}
}
});
// 创建集合
const Post = mongoose.model("Post", postSchema); //Posts
获取错误信息:error.errors['字段名称'].message
Post.create({
title: "aa",
age: 60,
categories: -"htm",
author: "pik"
})
.then((result) => {
console.log(result);
})
.catch((error) => {
// 获取错误信息对象
const erro = error.errors;
// 循环错误信息对象
for (attr in erro) {
console.log(erro[attr]["message"]);
}
});
# 2.7 集合关联
通常不同集合的数据之间是有关系的,例如文章信息和用户信息存储在不同集合中,但文章是某个用户发表的,要查询文章的所有信息包括发表用户,就需要用到集合关联。
使用 id 对集合进行关联 使用 populate 方法进行关联集合查询
// 定义用户集合规则
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
}
});
// 定义文章集合规则
const postSchema = new mongoose.Schema({
title: {
type: String
},
author: {
// 使用ID将文章集合和作者集合进行关联
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}
});
// 创建用户集合
const User = mongoose.model("User", userSchema);
// 创建文章集合
const Post = mongoose.model("Post", postSchema);
//联合查询
Post.find()
.populate("author")
.then((err, result) => console.log(result));
# 3. 案例 – 学生档案管理
# 3.1 案例介绍
目标:模板引擎应用,强化 node.js 项目制作流程。
知识点:http 请求响应、数据库、模板引擎、静态资源访问。
# 3.2 制作流程
建立项目文件夹并生成项目描述文件
创建网站服务器实现客户端和服务器端通信
连接数据库并根据需求设计学员信息表
创建路由并实现页面模板呈递
实现静态资源访问
实现学生信息添加功能
实现学生信息展示功能
npm ls -g --depth=0 #列出全局安装的第三方模块
npm install -g treer #安装treer第三方模块
treer -i "node_modules" #排除node_modules文件夹,生成目录
├─app.js 主服务
├─package-lock.json 依赖锁定文件
├─package.json 依赖描述文件
├─x.txt 项目描述文件
├─views 视图模板
| ├─index.art
| └-list.art
├─route 路由
| └index.js
├─public 静态资源
| ├─css
| | ├─list.css
| | └-main.css
├─model 模块
| ├─connect.js
| └-student.js
//connect.js
const mongoose = require("mongoose");
// 连接数据库
mongoose
.connect("mongodb://localhost/playground", {
useNewUrlParser: true
})
.then(() => console.log("数据库连接成功"))
.catch(() => console.log("数据库连接失败"));
//students.js
const mongoose = require("mongoose");
// 创建学生集合规则
const studentsSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 2,
maxlength: 10
},
age: {
type: Number,
min: 10,
max: 50
},
sex: {
type: String
},
email: String,
hobbies: [String],
collage: String,
enterDate: {
type: Date,
default: Date.now
}
});
// 创建学生信息集合
const Student = mongoose.model("Student", studentsSchema);
// 将学生信息集合进行导出
module.exports.Student = Student;
// app.js
// 引入http模块
const http = require("http");
// 引入模板引擎;
const template = require("art-template");
// 引入path模块;
const path = require("path");
// 引入静态资源访问模块
const serveStatic = require("serve-static");
// 引入处理日期的第三方模块
const dateformat = require("dateformat");
// 配置template的根目录
template.defaults.root = path.join(__dirname, "views");
// 给模板引擎导入日期格式模块
template.defaults.imports.dateformat = dateformat;
// 创建网站服务器
const app = http.createServer();
// 引入路由功能模块
const router = require("./route/index.js");
// 引入数据库连接模块;
require("./model/connect.js");
// 实现静态资源访问服务
const serve = serveStatic(path.join(__dirname, "public"));
// 当客户端访问服务器端的时候
app.on("request", (req, res) => {
// 启用路由功能
router(req, res, () => {});
// 启用静态资源访问服务功能
serve(req, res, () => {});
});
// 监听80端口
app.listen(80);
console.log("服务器启动成功");
# 3.3 第三方模块 router
功能:实现路由 使用步骤: 获取路由对象 调用路由对象提供的方法创建路由 启用路由,使路由生效
// route.js
// 引入router模块
const getRouter = require("router");
// 获取路由对象
const router = getRouter();
// 引入模板引擎
const template = require("art-template");
// 引入querystring模块
const querystring = require("querystring");
// 引入用户集合文件
const Student_model = require("../model/student");
const Student = Student_model.Student;
// 引入url模块
const url = require("url");
// 呈现默认页提示信息
router.get("/", (req, res) => {
let html = `
<p>您来到了互联网的荒原:</p>
<p>/add 学生档案信息添加页面</p>
<p>/list 学生档案信息列表页面</p>
`;
res.writeHead(200, {
"content-type": "text/html;charset=utf-8"
});
res.end(html);
});
// 呈递学生档案信息添加页面
router.get("/add", (req, res) => {
let html = template("index.art", {});
res.end(html);
});
// 呈递学生档案信息列表页面
router.get("/list", async (req, res) => {
// 查询学生信息
let students = await Student.find();
let html = template("list.art", {
students: students
});
res.end(html);
});
// 实现学生信息删除功能路由
router.get("/remove", async (req, res) => {
let { query } = url.parse(req.url, true);
let temp = query.id.replace(/"|'/g, "");
await Student.findOneAndDelete({
_id: temp
});
res.writeHead(301, {
Location: "/list"
});
res.end();
});
// 实现学生信息添加功能路由
router.post("/add", (req, res) => {
// 接收post请求参数
let formData = "";
req.on("data", (param) => {
formData += param;
});
req.on("end", async () => {
// 将用户的提交信息解析为对象结构
let student = querystring.parse(formData);
// 如果未设置用户名则不添加数据
if (student.name == "") {
res.writeHead(400, {
"content-type": "text/html;charset=utf-8"
});
res.end("请填写用户名");
}
if (student.name) {
await Student.create(student);
res.writeHead(301, {
Location: "/list"
});
res.end();
}
});
});
module.exports = router;
# 3.4 第三方模块 serve-static
功能:实现静态资源访问服务 步骤: 引入 serve-static 模块获取创建静态资源服务功能的方法 调用方法创建静态资源服务并指定静态资源服务目录 启用静态资源服务功能
const serveStatic = require("serve-static");
const serve = serveStatic("public");
server.on("request", () => {
serve(req, res);
});
server.listen(3000);