【Node.js】MongoDB数据库
数据库
一、基本概念
-
数据库即存储数据的仓库,可以将数据进行有序的分门别类的存储
它是独立于语言之外的软件,可以通过API去操作它。
-
一个数据库软件中可以包含多个数据仓库
-
每个数据仓库中可以包含多个数据集合
-
每个数据集合中可以包含多条文档(具体的数据)
术语 解释说明 database
数据库, 数据库软件中可以建立多个数据库 collection
集合,一组数据的集合 document
文档,一条具体的数据 filed
字段,文档中的属性名称
二、MongoDB数据库
01. 需要下载
-
MongoDB
数据库
-
MongoDB Compass
可视化数据库管理软件
-
Mongoose
使用
Node.js
操作MongoDB
数据库需要依赖第三方包mongoose
使用
npm install mongoose
命令下载
02. 启动MongoDB
-
使用命令行
net start mongoDB net stop mongoDB
03. 数据库连接
数据库的所有操作都是异步的
-
使用
mongoose
提供的connect
方法即可连接数据库mongoose.connect("mongodb://localhost/database") .then( () => { console.log("数据库连接成功"); }) .catch( (err) => { console.1og("数据库连接失败",err); })
-
mongoose.connect()
返回一个Promise
对象mongodb://localhost/database
mongodb://localhost
:数据库地址database
:数据库名称- 在
MongoDB
中不需要显式创建数据库 - 如果正在使用的数据库不存在,
Mongo DB
会自动创建
- 在
-
04. 创建集合
-
步骤
- 对集合设定规则
- 创建集合
创建
mongoose.Schema
构造函数的实例即可创建集合 -
语法
// 创建集合规则 const studentSchema = new mongoose.Schema({ // 这里是集合规则,包含属性和属性类型 name: String, age: Number, isGraduation: Boolean }); // 使用规则 创建集合 const Student = mongoose.model("Student", studentSchema);
-
创建集合规则:
mongoose.Schema("属性对象")
- 这是一个构造函数,创建集合即创建这个构造函数的实例对象
- 传递一个对象进去,对象中的属性,即为这个集合的文档的属性
-
创建集合:
mongoose.model("集合名称",集合规则)
-
集合名称首字母要大写,且创建后在数据库的名称实际为复数形式(小写的)
即集合名称为 Student
数据库名称为 students
-
它的返回值是这个集合的构造函数
-
-
05. 创建文档
实际上就是向集合中插入数据
数据库中有数据才会显示数据库
-
步骤
- 创建集合实例
- 调用实例对象下的
save
方法将数据保存到数据库中
-
语法
// 创建集合实例 const student = new Student({ name: "Ruo van", age: 24, isGraduation: true }); // 将数据保存到数据库中:调用实例的save()方法 student.save();
- 文档会自动生成一个唯一标识的_id属性
-
另一种方法
集合.create({属性对象},callback);
向集合中插入文档(数据)
Student.create({ name:"COmposition", age:18, isGraduation:true }, (err,doc) => { console.log(err); console.log(doc); });
// .create() 返回一个 Promise 对象 Student.create({}).then().catch();
-
直接导入文档数据
需要添加系统环境变量
mongoimport -d 数据库名称 -C 集合名称 --file 要导入的数据文件
-d
:被导入数据的数据库(database
)-c
:被导入数据的集合(collection
)--file
:要导入的数据文件
06. 查询文档
(1)根据条件查找文档
-
.find()
集合.find().then();
集合.find()
返回一个Promise
对象可以通过
.then()
获取结果
结果是数组形式,数组包含多个对象,每个对象就是一条数据
- 返回值始终是一个数组
- 条件为空,则查询所有文档
Student.find().then( (result) => { console.log(result); });
-
.findOne()
集合.findOne().then();
返回数据是一条对象形式的数据
- 返回一条数据,默认返回第一条数据
-
查询条件:
-
等于指定值
.find( {name: "username"} );
查询集合中 name 字段属性值为 username 的数据
-
大于、小于指定值:
$gt
、$lt
.find( { age: {$gt:20,$lt:30} } );
查询集合中 age 字段属性值 大于20小于20 的数据
-
包含指定值:
$in
.find( {hobbies: { $in: ["足球"] }} );
查询集合中 hobbies字段属性中包含 足球 的数据
-
-
查询字段
-
选择指定字段:
select()
.find().select("name email -_id");
在集合中指定字段 name email 中进行查询
默认会查询_id字段
在字段前添加短横线
-
可以不查询该字段
-
-
排序
-
对指定字段进行排序:
sort()
.find().sort("age");
对集合 根据指定字段 age 进行从小到大的排序
在字段前添加短横线
-
可以反向排序
-
-
跳过数据
-
跳过指定数量的数据:
skip()
.find().skip(2);
跳过前两条数据 进行查询
主要用于分页显示数据中
-
-
限制数量
-
限制数据查询 的数量:
limit()
.find().limit(2)
限制查询到的数据的数量 显示为 2条数据
主要用于分页显示数据中
-
07. 删除文档
-
删除单个文档
.findOneAndDelete();
查询指定数据并删除它
如果有多个,值删除第一条数据
返回Promise对象,返回的是被删除的那一条数据
可以通过
.then()
获得这个数据 -
删除多个文档
.deleteMany({查询条件});
删除匹配条件的多个数据
如果条件为空,则会删除所有数据
返回值是一个对象:
{n:2, ok:1}
n ——代表删除的数据数量
ok——代表删除操作成功
08. 更新文档
-
更新一个文档
.updateOne( {查询条件},{要修改的值} );
.updateOne( {age: 123},{age: 345} );
如果匹配多个文档,也只会更新第一条文档数据
返回一个Promise对象,用
.then()
方法返回返回值是一个对象:
n代表查询到的数据数量
nModified代表被更新的数据
ok属性为1,代表操作成功
-
更新多个文档
.updateMany( {查询条件},{要更改的值} );
.updateMany( {},{age: 000} );
查询条件为空,则更改所有数据
返回值同
updateOne()
09. mongoose验证
在创建集合规则时,可以设置当前字段的验证规则
验证失败则输入插入失败
// 创建集合规则(加入验证)
const studentSchema = new mongoose.Schema({
// 这里是集合规则,包含属性和属性类型
name: {
type: String,
required: true, // 设置为必须字段
minlength: 2, // 限制字符串最小长度
maxlength: 13, // 限制字符串最大长度
trim:true // 去除字符串两端空格
unique:true // 保证字段值唯一
},
age: {
type: Number,
min: 18, // 限制最小数值
max: 100 // 限制最大数值
},
birthday: {
type: Date,
default: Date.now() // 设置默认值
},
sex: {
type: String,
enum: ["male","female"] // 设置限制词
},
isGraduation: {
type: String,
validate: { //自定义验证规则
validator: (v) => {
return v > 60;
},
message: "传入的值不对" // 自定义错误信息
}
}
});
-
通过
required
对字段属性进行限制验证-
传入布尔值
true
,表示该字段为必须字段 -
传入数组,可自定义报错信息
required:[true,"该字段为必须字段"]
第一个参数为布尔值
第二个参数表示自定义报错信息
-
-
通过
minlength
和maxlength
对字段属性长度进行限制验证-
传入数字,以限制长度
-
传入数组,以自定义报错信息
minlength: [2, "最小长度为2"]
第一个参数为长度值
第二个参数为自定义报错信息
-
-
通过
min
和max
对字段属性数值大小进行限制验证 -
通过
default
设置字段属性的默认值 -
通过
enum
枚举可能传入的值enum: ["male","female"]
只能设置该字段属性值为
enum
中的值如果不是
enum
中的值,则验证失败 -
通过
validate
自定义验证器validate: { validator: (v) => { return v > 60; }, message: "传入的值不符合验证规则" }
validator
中的函数返回一个布尔值,true代表验证成功
false代表验证失败
v代表要验证的值
message
用来自定义错误信息
10. 获取错误信息
-
Promise
对象里的错误信息包含在errors
对象里message
属性里面 -
语法
.catch( (error) => { // 获取错误信息对象 const err = error.errors; // 遍历对象 for(let k in err){ // 打印错误信息 console.log( err[k].message ); } });
11. 集合关联
通常不同集合的数据之间是有关系的
-
使用
id
对集合进行关联 -
使用
populate()
方法查询// 两个集合:学生,分数 // 创建学生集合:规则+集合 const studengtSchema = new mongoose.Schema({ name: { type: String, required: true } // 添加用户字段 score: { // 类型是固定的,以关联 type: mongoose.Schema.Types.ObjectId, // 用ref关联Score集合 ref: "Score" } }); const Student = mongoose.model("Student",studengtSchema); // 创建分数集合:规则+集合 const scoreSchema = new mongoose.Schema({ English: { type: Number }, Chinese: { type: Number } }) const Score = mongoose.model("Score",scoreSchema); // 使用populate查询,查询条件为字段 Student.find().populate("score").then( (result)=>{ console.log(result) });
三、模板引擎
模板引擎是第三方模块,可以让开发者以更加友好的方式拼接字符串,使项目代码更加清晰、更加易于维护
01. art-template
模板引擎
-
下载与使用
npm install art-template
const template = require("art-template"); const str = template("模板路径", 数据);
-
语法示例:
<!-- 模板:index.art --> <div> <span>{{ data.name }}</span> <span>{{ data.age }}</span> </div>
- 模板路径一般为:
./views
- 模板文件后缀是
.art
,内容是html
格式
const html = template("./views/index.art", { data: { name: "Ruovan", age: 24 } });
-
template()
方法用来拼接字符串-
第一个参数是模板路径(绝对路径)
绝对路径需要引入
path
模块 -
第二个参数是要在模板中展示的数据
-
返回值是:拼接好的字符串
-
-
data
:在模板中展示的数据
- 模板路径一般为:
02.模板语法
-
art- template
同时支持两种模板语法- 标准语法:
{{ 数据 }}
- 原始语法:
<%= 数据 %>
标准语法可以让模板更容易读写,原始语法具有强大的逻辑处理能力
- 标准语法:
-
模板引擎默认不会解析
html
标签,要解析html
标签,需要- 标准语法:
{{@ 数据 }}
- 原始语法:
<%- 数据 %>
- 标准语法:
-
条件判断
-
标准语法
{{if 条件}} ... {{else if 条件}} ... {{/if}}
-
原始语法
<% if(value) { %> ... <% } %> <% if(value) { %> ... <% } else if(value) { %> ... <% } %>
<% if(条件) { %> ... <% }else if (条件) { %> ... <% > else { %> ... <% } %>
-
-
循环语法
-
标准语法
{{each data}} {{$value}} {{/each}}
-
标准语法
<% for(var i=0; i < data.length; i++) { %> <%= target[i] %> <% } %>
-
-
子模板
使用子模板可以将网站公共区块(头部、底部)抽离到单独的文件中
-
标准语法
{{ include "./header.art" }}
/header.art
是一个单独的模块 -
原始语法
<% include("./header.art") %>
-
-
模板继承
使用模板继承可以将网站HTML骨架抽离到单独的文件中
其他页面模板可以继承骨架文件
不同的页面的元素内容、元素样式不一致
因此需要预留位置以填充内容
使用
{{block "位置名称"}}...{{/block}}
来预留位置
通过
{{extend "模板"}}
来继承模板-
语法示例
<body> {{block "content"}} {{/block}} </body>
- 在
body
中预留这个位置 content
<!-- 继承模板 --> {{extend "./common/layout.art"}} <!-- 填充模板 --> {{block "content"}} <p>{{ data.name }}</p> {{/block}}
- 在
-
-
模板配置
- 向模板中导入变量
template.defaults.imports.变量名 = 变量值;
- 设置模板根目录
template.defaults.root=模板目录
- 设置模板默认后缀
template.defaults.extname=".art"
- 向模板中导入变量