1. init
为什么学习数据库???
动态网站中的数据都是存储在数据库中的!!!
数据库可以用来持久存储客户端通过表单收集的用户信息!!!
数据库软件本身可以对数据进行高效的管理!!!
术语 解释说明
database 数据库,mongoDB数据库软件中可以建立多个数据库
collection| 集合,一组数据的集合,可以理解为JavaScript中的数组 ```MYSQL中的表 ```
document 文档,一条具体的数据,可以理解为JavaScript中的对象 ```MYSQL中的行 ```
field 字段,文档中的属性名称,可以理解为JavaScript中的对象属性 ```MYSQL中的列 ```
npm install mongoose // 第三方模块
net start mongoDB // 启动数据库
为什么选择MongoDB?
=> 该数据库开发的API是采用JavaScript的语法;
存储的数据是以json对象格式;
更适合前端人员进行开发;
2. 插入数据
// 02_插入数据.js
/**
* mongoose: 第三方模块:需要下载
* 某个API文档: http://www.mongoosejs.net/docs/guide.html
*/
const mongoose = require('mongoose');
/* 1. 连接数据库: student就是数据库名, 没有则自动创建该数据库 */
mongoose.connect('mongodb://localhost/student', { useNewUrlParser: true , useUnifiedTopology: true })
.then(() => { console.log('connect database success!'); })
.catch((error)=>{ console.log(error,'connect database failed!'); });
/* 2. 创建集合规则: 使用Schema()就相当于创建字段; */
const courseSchema = new mongoose.Schema({
name: String,
author: String,
isPublished: Boolean
});
/* 3. 使用集合规则创建集合(集合 === 表),返回一个构造函数;
实际上此时就相当于创建了一张表, 表的字段就是刚才创建的集合规则;
使用model方法就相当于创建表; */
const Course = mongoose.model('Course', courseSchema); // 在MongoDB中显示为courses
/* 4. 插入数据
(1) 创建文档(相当于插入行,文档 === 行);
(2) 创建文档实际上就是向集合中插入数据;
*/
/*
法一:实例化构造函数(实例化集合)
const data1 = new Course({
name: 'nodeJS',
author: 'teacher',
isPublished: true
});
data1.save(); //表示插入到数据库中
*/
/* 法二:表示插入到数据库之中
(1) 插入单条数据
Course.create({name: 'JS', author: 'student', isPublished: false}, (error, doc) => {
// console.log(err); // 错误对象
console.log(doc); // 当前插入的文档
});
(2) 插入多条数据
user.create(
{ name: 'zhang', age: 12, password: '123456', hobbies: ['sing', 'dance'] },
{ name: 'wang', age: 23, password: '654321', hobbies: ['say', 'pao'] },
{ name: 'li', age: 45, password: '654321', hobbies: ['say', 'pao'] },
{ name: 'zhao', age: 24, password: '654321', hobbies: ['say', 'pao'] },
{ name: 'gao', age: 522, password: '654321', hobbies: ['say', 'pao'] }
);
*/
// create也返回Promise对象
Course.create({ name:'JavaScript', author:'GaoSan111', isPublished:false })
.then((doc)=> {
console.log(doc);
})
.catch((err)=>{
console.log(err);
});
3. 查询数据
// 03_查询数据.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('connect server success!');
})
.catch((error) => {
console.log(error, 'connect server failed!');
});
/*
此处注意:虽然是在图形化工具中创建了表;
但是要以代码的形式引用该表, 仍然需要使用.model()方法;
同时需要将.model()中的'User'设置为大写,
因为User会被默认转化为uses, 这可不就是我们所创建的表吗;
*/
const user = mongoose.model('User', new mongoose.Schema({
num: Number,
name: String,
age: Number,
hobbies: []
}));
/*
[1]. find(): 查询结果以数组形式进行返回, 查询所有文档(所有行);
user.find().then((result) => {
console.log(result);
});
*/
/*
[2]. 指定条件查询:
user.find({
_id: '6151d120b3d9e081c196d7c9'
}).then((result) => {
console.log(result);
});
*/
/*
[3]. findOne(): 不传参数,则默认返回第一个文档(第一行);
user.findOne({
name: 'Jing'
}).then((result) => {
console.log(result);
});
*/
/*
[4]. find条件系列查找:匹配大于,小于;
(1) $gt: 匹配大于;
(2) $lt:匹配小于;
//20 < age < 40
user.find({age: {$gt: 20, $lt: 40}}).then((result)=>{
console.log(result);
});
(3) $in: 匹配包含;
user.find({
hobbies: {
$in: ['sing']
}
}).then((result) => {
console.log(result);
});
(4) 选择要查询的字段:不显示_id字段;
使用字符串语法时,有 -前缀的路径会被排除,没有 -前缀的路径会被选择;
user.find().select('name password -_id').then((result) => {
console.log(result);
});
user.find({
age: {
$gt: 20,
$lt: 30
}
}).then((result) => {
console.log(result);
});
user.find({
hobbies: {
$in: ['dance']
}
}).then((result) => {
console.log(result);
});
user.find().select('num name -_id').then((result) => {
console.log(result);
});*/
/*
[5]. 排序:每个字段的排列顺序默认是升序,如果字段名有 - 前缀, 那么这个字段是降序;
升序:
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);
});
user.find().sort('-age').then((result) => {
console.log(result);
});
*/
/*
[6]. 限制查询:
跳过2条,限制查询的数量数量为2个
user.find().skip(2).limit(2).then((result) => {
console.log(result);
});
*/
user.find().skip(2).limit(2).then((result) => {
console.log(result);
});
4. 删除数据
// 04_删除数据.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('connect database success!');
})
.catch((error) => {
console.log(error, 'connect database failed!');
});
const user = mongoose.model('User', new mongoose.Schema({
num: Number,
name: String,
age: Number,
hobbies: []
}));
/*
1. 删除单条记录( findOneAndDelete() )
删除一个:如果查询结果包含多条记录,则删除匹配文档中的第一个,并返回删除的这个对象;
*/
/* */
user.findOneAndDelete({
name: 'GaoSan'
}).then((result) => {
console.log(result);
});
/*
2. 删除多条记录( deleteMany() )
*/
/*
此时会将表中的所有记录删除;
user.deleteMany({}).then((result) => {
console.log(result);
});
*/
5. 更新数据
// 05_更新数据.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('connect database success!');
})
.catch((error) => {
console.log(error, 'connect server failed!');
});
const user = mongoose.model('User', new mongoose.Schema({
num: Number,
name: String,
age: Number,
hobbies: []
}));
/*
1. 更新一条:(更改的条目,更改后条目的值)
*/
/* */
user.updateOne( { name: "XingWei" }, { name: "XingWeiZi" } ).then((result) => {
console.log(result);
});
/*
2. 更新多条:{} => 所有
user.updateMany({}, {
"age": 99
}).then((result) => {
console.log(result);
});
*/
6. 检验规则
// 06_校验规则.js
/*
在创建集合规则时,可以设置当前字段的验证规则,验证失败就则输入插入失败;
required:true 必传字段·minlength:3字符串最小长度
maxlength: 20字符串最大长度
min:2 数值最小为2
max:100 数值最大为100
enum: [html,'css] 插入的值必须是枚举中的任意一个
trim: true 去除字符串两边的空格
validate: 自定义验证器
default: 默认值
*/
//验证规则
const { log } = require('console');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('connect database success!');
})
.catch((error) => {
console.log(error, 'connect database failed!');
});
const personSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'the name filed must to be write!'], // 此时这个字段必须赋值,否则ERROR数组; 里的第二个表示自定义ERROR信息
minlength: [2, '不能小于2个字符'], // 针对String类型
maxlength: [5, '不能大于5个字符'],
trim: true,
},
age: {
type: Number,
min: 2, // 针对数值类型
max: [8, '传入的数值过大!'],
},
publishDate: {
type: Date,
default: Date.now // 默认值
},
category: {
type: String,
enum: {
values: ['c++', 'css', 'html'], // 只能取指定的值
message: '必须是指定值之一'
}
},
author: { //自定义规则
type: String,
validate: {
validator: (value) => { // value: 用户传递的值; 返回true,验证成功; 返回false,验证失败
return value && value.length > 4;
},
message: '传入的值不符合自定义规则' // 自定义错误信息
}
}
});
const person = mongoose.model('Teacher', personSchema);
person.create({
name: 'Good',
age: 6,
category: 'c+',
author: 'bdddd'
})
.then((result) => {
console.log(result);
})
.catch((error) => {
// console.log(error);
const errors = error.errors; // errors是一个对象
// console.log(errors);
for (var attr in errors) {
// console.log('***> ' + attr);
// console.log(errors[attr]);
console.log(errors[attr]['message']);
}
});
/*
也即是errors就是这样一个对象:
{
category: ValidatorError: 必须是指定值之一
at validate (F:\编程系列\Web前后端\Node.JS\07_数据库\node_modules\mongoose\lib\schematype.js:1237:13)
at F:\编程系列\Web前后端\Node.JS\07_数据库\node_modules\mongoose\lib\schematype.js:1220:7
at Array.forEach (<anonymous>)
at SchemaString.SchemaType.doValidate (F:\编程系列\Web前后端\Node.JS\07_数据库\node_modules\mongoose\lib\schematype.js:1165:14)
at F:\编程系列\Web前后端\Node.JS\07_数据库\node_modules\mongoose\lib\document.js:2506:18
at processTicksAndRejections (internal/process/task_queues.js:77:11) {
properties: {
validator: [Function (anonymous)],
message: '必须是指定值之一',
type: 'enum',
enumValues: [Array],
path: 'category',
value: 'c+'
},
kind: 'enum',
path: 'category',
value: 'c+',
reason: undefined,
[Symbol(mongoose:validatorError)]: true
}
}
*/
7. 集合校验
// 07_集合关联.js
/*
集合关联:通常不同集合的数据之间是有关系的; (也就是数据表的关联)
*/
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/student', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('connect database success!');
})
.catch((error) => {
console.log(error, 'connect database failed!');
});
/* 1. */
const authorSchema = new mongoose.Schema({
name: {
type: String,
required: true
}
});
const articleSchema = new mongoose.Schema({
title: {
type: String
},
//使用id将两个表进行关联;表示author这个字段和Author这个表进行关联
author: {
type: mongoose.Schema.Types.ObjectId, // _id, 存储的是作者的id
ref: 'Author' // 关联的表
}
});
/* 2. */
const author = mongoose.model('Author', authorSchema); // 作者表格
const article = mongoose.model('Article', articleSchema); // 文章表格
/*
// 1. 首先插入一个作者
author.create({name: '路遥'}).then((result)=>{
console.log(result);
});
结果如下:
_id : 615315fd1308cb61a87112dc
name : "路遥"
__v : 0
// 1. 然后将作者的_id字段值给拷过来, 赋值给article表中的author字段
article.create({ title: '完美世界', author: '615315fd1308cb61a87112dc' }).then((result) => {
console.log(result);
});
结果如下:
_id : 6153167832f6c458609154de
title : "完美世界"
author : 615315fd1308cb61a87112dc
__v : 0
// 3. 此后查询即可
*/
// 单纯的查询article表 => author字段显示的只是作者的_id字段的标识符
article.find()
.then((result) => {
console.log(result);
});
/*
[
{
_id: 6153167832f6c458609154de,
title: '完美世界',
author: 615315fd1308cb61a87112dc,
__v: 0
}
]
*/
// 联合查询populate(): 指定哪些字段需要关联查询(populated)其他文档;
// 此时在author字段, 已将作者的信息以对象的形式给展示出来了;
// ```populate()就是将author字段对应的作者信息给详细展示出来 ```;
article.find()
.populate('author')
.then((result) => {
console.log(result);
});
/*
[
{
_id: 6153167832f6c458609154de,
title: '完美世界',
author: { _id: 615315fd1308cb61a87112dc, name: '路遥', __v: 0 },
__v: 0
}
]
*/
联合查询解释: