MongoDB 数据库概述及环境搭建

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))
findOne方法返回一个对象。如果不加查询条件,那么返回的是当前集合中的第一条数据。

例子:继续编辑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: 传入的值不符合验证规则

create 方法返回的是 promise 对象,可以通过 .then() 方法拿到插入成功的返回值,所以我们也可以通过 .catch() 方法拿到插入失败的失败对象。
修改下 07.js 代码:
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));
ObjectId  就是  _id

例子:新建 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 时,实现删除用户功能

具体代码:

https://www.cnblogs.com/joe235/p/12869891.html 

原文地址:https://www.cnblogs.com/joe235/p/12803421.html