1 数据库概述及环境搭建
1.1 为什么要使用数据库
动态网站中的数据都是存储在数据库中的
数据库可以用来持久存储客户端通过表单收集的用户信息
数据库软件本身可以对数据进行高效的管理
1.2 什么是数据库
数据库即存储数据的仓库,可以将数据进行有序的分门别类的存储。它是独立于语言之外的软件,可以通过 API 去操作它。
常见的数据库软件有:mysql、mongoDB、oracle
1.3 MongoDB 数据库下载安装
下载地址:https://www.mongodb.com/download-center/community
还要下载 MongoDB Compass 图形界面软件,下载地址:https://www.mongodb.com/download-center/compass
在安装过程中,Custom 自定义安装可以选择安装路径,以后都选择默认安装就可以了。
相关概念:
一个网站有多个网站应用,所以一个数据库有多个 database(库)
一个网站应用有多种类数据,比如用户信息、商品信息,所以之下有 collection(类)
一类数据小有多条数据,所以之下有 document(条)
一条数据下有多种属性,所以之下有 field(属性)
1.4 MongoDB 可视化软件
MongoDB 可视化操作软件,是使用图形界面操作数据库的一种方式。
MongoDB Compass 可以在安装 MongoDB 的时候安装,也可以单独安装。
1.5 数据库相关概念
在一个数据库软件中可以包含多个数据仓库,在每个数据仓库中可以包含多个数据集合,每个数据集合中可以包含多条文档(具体的数据)。
1.6 Mongoose 第三方包
使用 Node.js 操作 MongoDB 数据库需要依赖 Node.js 第三方包 mongoose
它下面的 connect 方法可以连接数据库。
使用 npm install mongoose 命令下载
创建项目 database ,并在命令行工具切换到 database 目录下,进行安装,输入:
npm install mongoose
1.7 启动 MongoDB
在命令行工具中运行 net start mongoDB ,即可启动MongoDB,否则MongoDB将无法链接。
在命令行工具中,停止MongoDB,输入:
net stop MongoDB
启动MongoDB,输入:
net start mongoDB
1.8 数据库链接
使用 mongoDB 提供的 connect 方法即可连接数据库
基本语法:
mongoose.connect('mongodb://localhost/playground') .then(() => console.log('数据库连接成功')) .catch(err => console.log('数据库连接失败',err));
例子:
新建 01.js 文件,先引入 mongoose:
const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/playground') .then(() => console.log('数据库连接成功')) .catch((err) => console.log(err,'数据库连接失败'))
回到命令行工具,输入:
node 01.js
结果是:
可以看到数据库连接成功,但是在之前有一些 mongoose 的提示,说是:当前的 current URL 解析器,已经被废弃掉了,在将来的版本中将会被删除掉,然后让你使用新的解析器。{ useNewUrlParser: true, useUnifiedTopology: true }
修改下代码:
// 引入mongoose 第三方模块,用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 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 构造函数的实例即可创建集合。
语法:
// 设定集合规则 const courseSchema = new mongoose.Schema({ name: String, author: String, isPublished: Boolean }); // 创建集合并应用规则 const Course = mongoose.model('Course', courseSchema); // courses
mongoose.model 创建集合,第一个参数是集合的名称,集合名称的首字母应该大写,比如:Course,当实际上 mongoose 在数据库中创建的集合名称是:courses,是小写,后面加 s 代码复数,因为是集合。Course 接收的是 mongoose.model 的返回值:构造函数。
例子:新建 02.js 文件:
// 引入mongoose 第三方模块,用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true, useUnifiedTopology: true }) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch((err) => console.log(err,'数据库连接失败')); // 设定集合规则 const courseSchema = new mongoose.Schema({ name: String, author: String, isPublished: Boolean }); // 使用规章创建集合 const Course = mongoose.model('Course', courseSchema); // courses
回到命令行工具,输入:
node 02.js
提示:数据库连接成功。
然后打开 MongoDBCompass 软件,刷新后并没有看到我们写的 playground 数据库,是因为没有为集合插入数据,所以就没有创建数据库。下面我们需要插入一条数据。
2.2 创建文档
创建文档实际上就是向集合中插入数据。
分为两步:
1)创建集合实例
2)调用实例对象下的 save 方法,将数据保存到数据库中
基础语法:
// 创建集合实例 const course = new Course({ name: 'Node.js course', author: 'joe', tags: ['node', 'backend'], isPublished: true }); // 将数据保存到数据库中 course.save();
继续编辑 02.js 文件:
// 引入mongoose 第三方模块,用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true, useUnifiedTopology: true }) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch((err) => console.log(err,'数据库连接失败')); // 设定集合规则 const courseSchema = new mongoose.Schema({ name: String, author: String, isPublished: Boolean }); // 使用规章创建集合 const Course = mongoose.model('Course', courseSchema); // courses // 创建集合实例 const course = new Course({ name: 'Node.js 基础', author: 'joe', isPublished: true }); // 将数据保存到数据库中 course.save();
回到命令行工具中,重新运行,输入:
node 02.js
然后打开 MongoDBCompass 软件,刷新后就可以看到 playground 数据库了
点击 courses 集合,可以看到里面有一条数据。
_id 属性段是当前数据的唯一标识,是数据库自动生成的。
还有一种方式可以向集合中插入文档。
语法:
Course.create({name: 'Node.js 基础', author: 'joe', isPublished: true}, (err, doc) => { // 错误对象 console.log(err) // 当前插入的文档 console.log(doc) });
例子:
新建 03.js 文件:
// 引入mongoose 第三方模块,用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true, useUnifiedTopology: true }) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch((err) => console.log(err,'数据库连接失败')); // 设定集合规则 const courseSchema = new mongoose.Schema({ name: String, author: String, isPublished: Boolean }); // 使用规章创建集合 // 第1个参数代表集合名称 // 第2个参数代表集合规则 const Course = mongoose.model('Course', courseSchema); // courses // 向集合中插入文档 Course.create({name: 'JavaScript', author: 'joe', isPublished: false}, (err, result) => { // 错误对象 console.log(err) // 当前插入的文档 console.log(result) });
回到命令行工具,输入:
node 03.js
结果:
第1个参数 null 代表:插入是成功的;第2个参数是插入文档的那一条数据。
回到 MongoDBCompass 软件,点击刷新,可以看到有2条数据了:
关于数据库的所有操作,都是异步操作。
mongoose 当中提供的 API 也支持 promise 的方式:
Course.create({name: 'JavaScript 基础', author: 'joe', isPublished: true}) .then(doc => console.log(doc)) .catch(err => console.log(err))
例子:修改下 03.js 文件:
// 引入mongoose 第三方模块,用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true, useUnifiedTopology: true }) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch((err) => console.log(err,'数据库连接失败')); // 设定集合规则 const courseSchema = new mongoose.Schema({ name: String, author: String, isPublished: Boolean }); // 使用规章创建集合 // 第1个参数代表集合名称 // 第2个参数代表集合规则 const Course = mongoose.model('Course', courseSchema); // courses // 向集合中插入文档 // Course.create({name: 'JavaScript', author: 'joe', isPublished: false}, (err, result) => { // // 错误对象 // console.log(err) // // 当前插入的文档 // console.log(result) // }); Course.create({name: 'JavaScript123', author: 'joe', isPublished: false}) .then(result => { console.log(result) }) .catch(err => { console.log(err) })
回到命令行工具中重新运行 03.js
结果:
回到 MongoDBCompass 软件,点击刷新,可以看到有3条数据了。
总结:可以通过 create 方法来向集合中插入数据,它有两种接收异步 API 的方式:第一种通过回调函数的方式,第二种通过 promise 对象的方式。
2.3 mongoDB 数据库导入数据
把现成的数据插入到数据库中,需要用 到mongoDB 提供的命令:mongoimport
mongoimport -d 数据库名称 -c 集合名称 --file 要导入的数据文件
在命令行工具中输入:mongoimport,提示无法识别,并没有找到 mongoimport 的可执行文件,我们需要手动将命令的所在的目录添加到系统环境变量 path 中去,命令行工具才能找到 mongoimport 命令的可执行文件。命令的所在目录就是mongoDB 数据库的安装目录。
打开本地电脑的 mongoDB 安装目录,在里面找到 bin目录,打开可以看到 mongoimport.exe 文件,并复制它的目录:
把复制好的目录添加到系统的环境变量 path 中:
保存后,需要把命令行工具进行重启,记得重启好后,要切换到 database 目录下。
然后将准备好的 user.json 文件中的数据,导入到数据库中。在命令行输入:
mongoimport -d playground -c users --file ./user.json
结果:表示找到了本机当做的数据库,导入了6个文档。
然后打开 Compass 软件,点击刷新,可以看到新增加了一个 users 集合,里面有6条数据:
2.4 查询文件
语法:
// 根据条件查找文档(条件为空则查找所有文档) Course.find().then(result => console.log(result))
find() 返回的是:文档集合。
例子:
新建 04.js 文件:
// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); // 创建集合规则 const userSchema = new mongoose.Schema({ name: String, age: Number, email: String, password: String, hobbies: [String] }); // 使用规则创建集合 const User = mongoose.model('User', userSchema); // 查询用户集合中的所有文档 User.find().then(result => console.log(result));
切换到命令行工具,输入:
node 04.js
可以看到结果:返回的是一个数组,数组里包含了多个对象。
可以在 find() 方法里传递一个对象,那么这个对象就是查询条件。
例如:查询用户 id 为多少的,在 Compass 里,随便复制一个 id 值,修改下 04.js 文件:
// 使用规则创建集合 const User = mongoose.model('User', userSchema); // 查询用户集合中的所有文档 // User.find().then(result => console.log(result)); // 通过_id字段查找文档 User.find({_id: '5c09f1e5aeb04b22f8460965'}).then(result => console.log(result))
在命令行工具中输入:node 04.js
可以看到查询结果:
可以看到返回的还是一个数组,里面有一条数据。
总结:通过 find() 方法查询出的数据,无论有多少,它返回的都是一个数组。如果查找的数据不存在,那么会返回一个空数组。
另外一个方法 findOne:
语法:
// 根据条件查找文档 Course.findOne({name: 'node.js 基础'}).then(result => console.log(result))
例子:继续编辑04.js 文件:
// 查询用户集合中的所有文档 // User.find().then(result => console.log(result)); // 通过_id字段查找文档 // User.find({_id: '5c09f1e5aeb04b22f8460965'}).then(result => console.log(result)) // findOne方法返回一条文档 默认返回当前集合中的第一条文档 User.findOne().then(result => console.log(result))
回到命令工具,输入:node 04.js
结果:返回的是一个对象(第一条数据文档)
例子:查询名字是“李四”的数据:
User.findOne({name: '李四'}).then(result => console.log(result))
匹配大于$gt 小于$lt:
语法:
// 匹配大于 小于 User.find({age: {$gt: 20, $lt: 50}}).then(result => console.log(result))
例子:04.js 文件:
// 查询用户集合中年龄字段大于20并且小于40的文档 User.find({age: {$gt: 20, $lt: 40}}).then(result => console.log(result))
命令行工具中,输入:node 04.js
结果:
匹配包含 $in:
语法:
// 匹配包含 User.find({hobbies: {$in: ['足球']}}).then(result => console.log(result))
例子:
// 查询用户集合中hobbies字段值包含足球的文档 User.find({hobbies: {$in: ['足球']}}).then(result => console.log(result))
结果是:
选择要查询的字段 select:
// 选择要查询的字段 User.find().select('name email').then(result => console.log(result))
例子:
// 选择要查询的字段 名字和邮件地址 User.find().select('name email').then(result => console.log(result))
结果:
可以看到 _id 是默认字段,自动查询出来的。如果不想查询出 _id 字段,写作:-_id
例子:
// 选择要查询的字段 User.find().select('name email -_id').then(result => console.log(result))
结果:
对查询出来的数据进行排序 sort
语法:
// 将数据按照年龄进行排序 User.find().sort('age').then(result => console.log(result))
例子:根据年龄字段进行升序排列
// 根据年龄字段进行升序排列 User.find().sort('age').then(result => console.log(result)) // 根据年龄字段进行降序排列 User.find().sort('-age').then(result => console.log(result))
跳过数据skip 和 限制查询数量limit
语法:
// skip 跳过多少条数据 limit 限制查询数量 User.find().skip(2).limit(3).then(result => console.log(result))
例子:
// 查询文档跳过前两条结果 限制显示3条结果 User.find().skip(2).limit(3).then(result => console.log(result))
2.5 删除文档
删除单个文档:
// 删除单个 Course.findOneAndDelete({}).then(result => console.log(result))
如果查询条件包含了多条文档,那么会将第一个匹配的文档删除。返回值是删除的这条文档。
例子:新建 05.js 文件:
// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); // 创建集合规则 const userSchema = new mongoose.Schema({ name: String, age: Number, email: String, password: String, hobbies: [String] }); // 使用规则创建集合 const User = mongoose.model('User', userSchema); // 查找到一条文档并且删除 // 返回删除的文档 // 如何查询条件匹配了多个文档 那么将会删除第一个匹配的文档 User.findOneAndDelete({_id: '5c09f267aeb04b22f8460968'}).then(result => console.log(result))
在命令行工具,输入:
node 05.js
返回一条文档,也就是被删除的这条数据。
然后打开 Compass 软件,刷新后可以看到只剩下5条数据了,‘王五’的那条数据被删除了。
删除多个文档:
// 删除多个 User.deleteMany({}).then(result => console.log(result))
依然返回 promise 对象。
例子:05.js 文件:
// 删除多条文档,如果查询条件为空对象,那么会把数据库中 User 集合中的所有文档都删除 User.deleteMany({}).then(result => console.log(result))
回到命令行工具,输入:node 05.js
结果:
然后打开 Compass 软件,刷新后可以看到 users 这个集合里是空的了。
2.6 更新文档
更新单个文档:
// 更新单个文档 User.updateOne({查询条件}, {要修改的值}).then(result => console.log(result))
如果有多个查询结果,会更新第一条文档。
例子:
因为我们上面把users集合里的数据都删除了,下面要重新导入下 user.json 文件中的数据,在命令行工具中输入:
mongoimport -d playground -c users --file ./user.json
然后新建 06.js 文件:
// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); // 创建集合规则 const userSchema = new mongoose.Schema({ name: String, age: Number, email: String, password: String, hobbies: [String] }); // 使用规则创建集合 const User = mongoose.model('User', userSchema); // 更新集合中的单个文档 User.updateOne({name: '李四'}, {age: 120, name: '李狗蛋'}).then(result => console.log(result))
在命令行工具输入:
node 06.js
结果:
打开 Compass 软件,刷新后可以看到 users 这个集合中的“李四”,变为了“李狗蛋”,年龄改为了120。
更新多个文档:
// 更新多个文档 User.updateMany({查询条件}, {要更改的值}).then(result => console.log(result))
查询条件为空的话,表示更新所有文档。
例子:修改 06.js 文件:
// 更新集合中的单个文档 // User.updateOne({name: '李四'}, {age: 120, name: '李狗蛋'}).then(result => console.log(result)) // 更新集合中的多个文档 User.updateMany({}, {age: 56}).then(result => console.log(result))
在命令行工具中输入:
node 06.js
然后结果可以看到所有文档的年龄都改为了 56。
2.6 mongoose 验证
在创建集合规则时,可以设置当前字段的验证规则,验证失败则输入插入失败。
● required.true 必传字段
例子:新建 07.js 文件:
// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); const postSchema = new mongoose.Schema({ title: { type: String, required: true } }); // 使用规则创建集合 const Post = mongoose.model('Post', postSchema); Post.create({}).then(result => console.log(result))
在命令行工具输入:node 07.js,会提示错误信息。
因为设置 title 字段为必传字段,但是插入文档的时候为空对象,所以会提示错误。
如果把 required: true 去掉,在重新运行 07.js,即使插入空对象,也会提示插入成功。然后打开 Compass 软件,会发现多了一个 posts 集合。
如果想自定义报错信息的话,可以修改设置为:
title: { type: String, required: [true, '请传入文章标题'] }
第一个参数 true 为必传,第二个参数就是自定义的错误信息。
在命令行工具中重新输入:node 07.js
结果的自定义错误信息:
● minlength 最小长度
● maxlength 最大长度
title: { type: String, required: [true, '请传入文章标题'], minlength: 2, maxlength: 5 }
例子:
const postSchema = new mongoose.Schema({ title: { type: String, required: [true, '请传入文章标题'], minlength: 2, maxlength: 5 } }); // 使用规则创建集合 const Post = mongoose.model('Post', postSchema); Post.create({title: 'a'}).then(result => console.log(result))
运行后会提示:
Post validation failed: title: Path `title` (`a`) is shorter than the minimum allowed length (2).
在修改代码为 title: 'aaaaaa'
运行后会提示:
Post validation failed: title: Path `title` (`aaaaaa`) is longer than the maximum allowed length (5).
当然 minlength 和 maxlength 也可以自定义错误信息,格式同 required 一样:
minlength: [2, '文章标题长度不能小于2'],
maxlength: [5, '文章标题长度最大不能超过5']
● trim: true 去除字符串两端空格
例子:
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
const postSchema = new mongoose.Schema({
title: {
type: String,
required: [true, '请传入文章标题'],
minlength: [2, '文章标题长度不能小于2'],
maxlength: [5, '文章标题长度最大不能超过5'],
trim: true
}
});
// 使用规则创建集合
const Post = mongoose.model('Post', postSchema);
Post.create({title: ' aaa '}).then(result => console.log(result))
在命令行工具中输入: node 07.js
结果:可以看到两端的空格没有了,标题就是:aaa
● min: 2 数值最小为2
● max: 100 数值最大为100
例子: 修改 07.js 文件
// 引入mongoose第三方模块 用来操作数据库
const mongoose = require('mongoose');
// 数据库连接
mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true})
// 连接成功
.then(() => console.log('数据库连接成功'))
// 连接失败
.catch(err => console.log(err, '数据库连接失败'));
const postSchema = new mongoose.Schema({
title: {
type: String,
// 必选字段
required: [true, '请传入文章标题'],
// 字符串的最小长度
minlength: [2, '文章标题长度不能小于2'],
// 字符串的最大长度
maxlength: [5, '文章标题长度最大不能超过5'],
// 去除字符串两边的空格
trim: true
},
age: {
type: Number,
min: 18,
max: 100
}
});
// 使用规则创建集合
const Post = mongoose.model('Post', postSchema);
Post.create({title: 'aa', age: 10}).then(result => console.log(result))
运行后结果提示报错:
Post validation failed: age: Path `age` (10) is less than minimum allowed value (18).
当然如果想自定义错误信息,格式和上面是一样的。
● default 默认值
例子:修改 07.js
// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); const postSchema = new mongoose.Schema({ title: { type: String, // 必选字段 required: [true, '请传入文章标题'], // 字符串的最小长度 minlength: [2, '文章标题长度不能小于2'], // 字符串的最大长度 maxlength: [5, '文章标题长度最大不能超过5'], // 去除字符串两边的空格 trim: true }, age: { type: Number, min: 18, max: 100 }, publishDate: { type: Date, // 默认值 default: Date.now } }); // 使用规则创建集合 const Post = mongoose.model('Post', postSchema); Post.create({title: 'aa', age: 60}).then(result => console.log(result))
在命令行工具中输入:node 07.js
结果:
回到 Compass 软件,发现 posts 集合多了一条文档:
● enum: ["html", "css", "javascript", "node.js"] 枚举,列举出当前字段可以拥有的值(只能传固定的一些值)
例子:修改 07.js
// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); const postSchema = new mongoose.Schema({ title: { type: String, // 必选字段 required: [true, '请传入文章标题'], // 字符串的最小长度 minlength: [2, '文章标题长度不能小于2'], // 字符串的最大长度 maxlength: [5, '文章标题长度最大不能超过5'], // 去除字符串两边的空格 trim: true }, age: { type: Number, // 数字的最小范围 min: 18, // 数字的最大范围 max: 100 }, publishDate: { type: Date, // 默认值 default: Date.now }, category: { type: String, // 枚举 列举出当前字段可以拥有的值 enum: ['html', 'css', 'javascript', 'node.js'] } }); // 使用规则创建集合 const Post = mongoose.model('Post', postSchema); Post.create({title: 'aa', age: 60, category:'java'}).then(result => console.log(result))
结果:提示报错信息
Post validation failed: category: `java` is not a valid enum value for path `category`.
把代码中的类型修改为:html
Post.create({title: 'aa', age: 60, category:'html'}).then(result => console.log(result))
就可以运行插入成功了。
● validate:自定义验证器,mongoose 提供了自定义验证规则
例子:修改 07.js
// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); const postSchema = new mongoose.Schema({ title: { type: String, // 必选字段 required: [true, '请传入文章标题'], // 字符串的最小长度 minlength: [2, '文章标题长度不能小于2'], // 字符串的最大长度 maxlength: [5, '文章标题长度最大不能超过5'], // 去除字符串两边的空格 trim: true }, age: { type: Number, // 数字的最小范围 min: 18, // 数字的最大范围 max: 100 }, publishDate: { type: Date, // 默认值 default: Date.now }, category: { type: String, // 枚举 列举出当前字段可以拥有的值 enum: ['html', 'css', 'javascript', 'node.js'] }, author: { type: String, validate: { validator: v => { // 返回一个布尔值 // true 表示验证成功;false 表示验证失败 // v 表示要验证的值 return v && v.length > 4 }, // 自定义错误信息 message: '传入的值不符合验证规则' } } }); // 使用规则创建集合 const Post = mongoose.model('Post', postSchema); Post.create({title: 'aa', age: 60, category:'html', author: 'bd'}).then(result => console.log(result))
运行后结果:
Post validation failed: author: 传入的值不符合验证规则
Post.create({title: 'aa', age: 60, category:'html', author: 'bd'}) .then(result => console.log(result)) .catch(error => console.log(error))
重新运行:node 07.js
结果:author 字段插入的值不符合规章
如果插入文档中有多个字段不符合规则:
Post.create({title: 'aa', age: 60, category:'java', author: 'bd'}) .then(result => console.log(result)) .catch(error => console.log(error))
运行后的结果:category 字段和 author 字段插入的值都不符合规章
可以看到第一层是 errors,然后里面有 category 对象和 author 对象,再里面的 message 字段为错误信息。
那么我们就可以把 .cacth 里面写一个遍历数组,把错误信息都输出出来:
Post.create({title: 'aa', age: 60, category:'java', author: 'bd'}) .then(result => console.log(result)) .catch(error => { // 获取错误信息对象 const err = error.errors // 循环错误信息对象 for(var i in err) { console.log(err[i].message); // console.log(err[i]['message']); } })
重新运行后可以看到结果:
下面我们把第一个错误信息也自定义下:
category: { type: String, // 枚举 列举出当前字段可以拥有的值 enum: { values: ['html', 'css', 'javascript', 'node.js'], message: '分类名称要在一定的范围内才可以' } },
重新运行后的结果:
3.7 集合关联
通常不同集合的数据之间是有关系的,例如文章信息和用户信息存储在不同的集合中,但文章是某个用户发表的,要查询文章的所有信息包括发表用户,就需要用到集合关联。
● 使用 id 对集合进行关联
● 使用 populate 方法进行关联集合查询
语法:
// 用户集合 const User = mongoose.model('User', new mongoose.Schema({ name: { type: String} })); // 文章集合 const Post = mongoose.model('Post', new mongoose.Schema({ title: { type: String }, // 使用 id 将文章集合和用户集合进行关联 author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } })); // 联合查询 Post.find() .populate('author') .then((err, result) => console.log(result));
例子:新建 08.js 文件:
// 引入mongoose第三方模块 用来操作数据库 const mongoose = require('mongoose'); // 数据库连接 mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true}) // 连接成功 .then(() => console.log('数据库连接成功')) // 连接失败 .catch(err => console.log(err, '数据库连接失败')); // 用户集合规则 const userSchema = new mongoose.Schema({ name: { type: String, required: true } }); // 文章集合规则 const postSchema = new mongoose.Schema({ title: { type: String }, // 使用 id 将文章集合和用户集合进行关联 author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } }); // 用户集合 const User = mongoose.model('User', userSchema); // 文章集合 const Post = mongoose.model('Post', postSchema); // 创建用户 User.create({name: 'joe'}).then(result => console.log(result));
在命令行工具中,输入:
node 08.js
结果:创建用户成功
回到 Compass 软件中,刷新可以看到:创建的用户 joe
然后进行创建文章:
// 创建用户 // User.create({name: 'joe'}).then(result => console.log(result)); // 创建文章 author 值为用户的 id Post.create({titile: '123', author: '5eb9057561a07b1680de2a21'}).then(result => console.log(result));
运行后可以看到结果:
回到 Compass 软件中,刷新可以看到:创建的文章
然后进行查询:
// 创建用户 // User.create({name: 'joe'}).then(result => console.log(result)); // 创建文章 author 值为用户的 id // Post.create({title: '123', author: '5eb9057561a07b1680de2a21'}).then(result => console.log(result)); // 联合查询 Post.find().populate('author').then(result => console.log(result))
重新运行后结果:
2.8 案例:用户信息增删改查
1、搭建网站服务器:实现客户端与服务端的通信
2、连接数据库,创建用户集合,向集合中插入文档
3、当用户访问 /list 时,将所有用户信息查询出来
4、将用户信息和表格 HTML 进行拼接,并将拼接结果响应回客户端
5、当用户访问 /add 时,呈现表单页面,并实现添加用户信息功能
6、当用户访问 /modify 时,呈现修改页面,并实现修改用户信息功能
7、当 用户访问 /delete 时,实现删除用户功能
具体代码: