一、Mongoose
:对象文档模型库
1、官网:
2、作用:
方便使用代码操作
mongodb
数据库
3、安装 Mongoose
:
npm i mongoose
4、连接数据库:
终端要一直运行服务端程序!!!
① 引用 mongoose
模块:
const mongoose = require('mongoose')
② 数据库建立连接:
端口号默认是 27017
(1)创建默认全局连接:
mongoose.connect('mongodb://域名:端口号/数据库名称')
(2)创建独立连接实例:
mongoose.createConnection(mongodb://域名:端口号/数据库名称')
③ 数据库关闭连接:
(1)独立连接关闭:
实例对象.close()
(2)全局连接关闭(默认):
mongoose.disconnect()
或者mongoose.close()
④ 访问数据库连接实例:
(1)独立连接对象:
mongoose.createConnection()
函数调用后,返回新的连接对象
(2)全局连接对象(默认):
存储在
mongoose.connection
⑤ 设置数据库连接回调:
(1)连接成功的回调:
a、 once
:回调函数只会在第一次连接成功时执行
适合一次性操作(如初始化)
db.once('open', () => {
console.log('首次连接成功');
});
b、 on
:回调函数每次连接成功都会执行
适合错误处理(需要持续监控)、连接状态变化(需持久响应)
db.on('open', () => {
console.log('数据库连接已建立(每次重连都会触发)');
});
(2)连接失败的回调:
先执行 连接断开 的回调,再执行 连接失败 的回调
db.on('error', () => {
console.log('数据库连接失败')
})
(3)连接断开的回调:
db.on('disconnected', () => {
console.log('数据库断开连接')
})
(4)连接关闭的回调:
先执行 连接断开 的回调,再执行 连接关闭 的回调
db.on('close', () => {
console.log('数据库关闭连接')
})
⑤ 完整练习代码:
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、全局连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 测试数据库连接失败
// mongoose.connect('mongodb://127.0.0.1:27018/a')
// 3、获取全局连接的实例
const db = mongoose.connection;
// 获取独立连接的实例
// let db = mongoose.createConnection('mongodb://127.0.0.1:27017/a')
// 4、设置回调
db.once('open', () => {
console.log('数据库连接成功')
})
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
// 数据库关闭连接
// setTimeout(() => {
// db.close()
// }, 5000)
5、文档的字段类型:
① 字符串: String
② 数字: Number
③ 布尔值: Boolean
④ 数组: Array
或者 []
⑤ 日期: Date
⑥ Buffer
对象: Buffer
⑦ 任意类型: mongoose.Schema.Types.Mixed
⑧ 对象 ID
: mongoose.Schema.Types.ObjectId
主要用于定义外键,即将另外一个文档的
id
存到 本文档中,进行联合查询
⑨ 高精度数字: mongoose.Schema.Types.Decimal128
6、验证器:
文档属性值(字段值)的验证
① 设置必填项:required: true
② 设置默认值:default: 数据
③ 设置枚举:enum: [数据1, 数据2,...]
属性值(字段值)必须是当前枚举中的数据
④ 唯一值:unique: true
如果在已有的集合中进行设置,则无用;需要新建集合才生效
属性值不允许重复!必须是唯一的!
⑤ 完整语法:
属性名:{
type: 属性值的类型,
验证器
}
⑥ 以 新增文档 为例的完整代码:
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 3、获取连接的实例
const db = mongoose.connection;
// 4、设置回调
db.once('open', () => {
let personType = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
sex: {
type: String,
enum: ['男', '女']
},
grade: {
type: String,
unique: true
},
hobby: Array
})
let person = mongoose.model('persons', personType)
// 使用 `Promise` 语法新增数据
person.create({
name: 'red',
age: undefined,
sex: '男',
grade:'大二',
hobby: ['吃饭']
}).then((data) => {
// 新增后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('新增数据失败',err)
})
console.log('数据库连接成功')
})
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
7、文档的操作:
在数据库 连接成功的回调函数 中编写代码
① 创建文档的结构对象:
文档的结构:
集合中文档的属性及属性值的类型
let 文档结构对象名 = new mongoose.Schema({
属性名1: 属性值的类型1,
属性名2: 属性值的类型2,
...
})
② 创建模型对象:
模型对象:
对文档进行封装后,可以操作的对象
let 模型对象名 = mongoose.model(集合名,文档的结构对象名)
③ 创建文档:
如果属性名写错了,则忽略该属性
(1)使用 async/await
语法新增数据:
async function 新增文档的函数名(模型对象名) {
try {
const user = await 模型对象名.create(数据对象);
// 新增后的文档对象
console.log(user);
} catch (err) {
console.log('新增数据失败',err)
}
}
(2)使用 Promise
语法新增数据:
模型对象名.create(数据对象).then((data) => {
// 新增后的文档对象
console.log(data);
}).catch((err) => {
console.log('新增数据失败',err)
})
(3)完整的代码:
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 3、获取连接的实例
const db = mongoose.connection;
// 4、设置回调
db.once('open', () => {
let personType = new mongoose.Schema({
name: String,
age: Number,
sex: String,
hobby: Array
})
let person = mongoose.model('persons', personType)
// 新增数据
// createData(person)
// 使用 `Promise` 语法新增数据
person.create({
name: 'lisi',
age: 23,
sex: '女',
hobby: ['打球']
}).then((data) => {
// 新增后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('新增数据失败',err)
})
console.log('数据库连接成功')
})
// 使用 `async/await` 语法新增数据
async function createData(person) {
try {
const user = await person.create({
name: 'zhangsan',
age: 20,
sex: '男',
hobby: ['吃饭', '睡觉', '打豆豆']
});
// 新增后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('新增数据失败',err)
}
}
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
④ 删除文档:
(1)使用 async/await
语法删除数据:
a、删除一个文档(匹配的第一个):
async function deleteData(person) {
try {
const user = await person.deleteOne(删除的条件);
// 删除后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('删除数据失败',err)
}
}
b、删除多个文档(匹配的所有的):
async function deleteData(person) {
try {
const user = await person.deleteMany(删除的条件);
// 删除后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('删除数据失败',err)
}
}
(2)使用 Promise
语法删除数据:
a、删除一个文档(匹配的第一个):
模型对象名.deleteOne(删除条件).then((data) => {
// 删除后的文档对象
console.log(data);
}).catch((err) => {
console.log('删除数据失败',err)
})
b、删除多个文档(匹配的所有的):
模型对象名.deleteMany(删除条件).then((data) => {
// 删除后的文档对象
console.log(data);
}).catch((err) => {
console.log('删除数据失败',err)
})
(3)完整的代码:
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 3、获取连接的实例
const db = mongoose.connection;
// 4、设置回调
db.once('open', () => {
let personType = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
sex: {
type: String,
enum: ['男', '女']
},
grade: {
type: String,
unique: true
},
hobby: Array
})
let person = mongoose.model('persons', personType)
// 删除数据
deleteData(person)
// 使用 `Promise` 语法删除数据
// 删除一条
// person.deleteOne({age: 0}).then((data) => {
// 删除多条
// person.deleteMany({age: 25}).then((data) => {
// // 删除后的文档对象
// console.log(data);
// // 断开数据库连接。项目运行过程中,不会添加该代码
// mongoose.disconnect()
// }).catch((err) => {
// console.log('删除数据失败',err)
// })
console.log('数据库连接成功')
})
// 使用 `async/await` 语法删除数据
async function deleteData(person) {
try {
// 删除一条
// const user = await person.deleteOne({age: 0});
// 删除多条
const user = await person.deleteMany({age: 25});
// 删除后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('删除数据失败',err)
}
}
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
⑤ 更新文档:
(1)使用 async/await
语法更新数据:
a、更新一个文档(匹配的第一个):
async function updateData(person) {
try {
const user = await person.updateOne(查找数据的条件, 新数据);
// 更新后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('更新数据失败',err)
}
}
b、更新多个文档(匹配的所有的):
async function updateData(person) {
try {
const user = await person.updateMany(查找数据的条件, 新数据);
// 更新后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('更新数据失败',err)
}
}
(2)使用 Promise
语法更新数据:
a、更新一个文档(匹配的第一个):
模型对象名.updateOne(查找数据的条件, 新数据).then((data) => {
// 更新后的文档对象
console.log(data);
}).catch((err) => {
console.log('更新数据失败',err)
})
b、更新多个文档(匹配的所有的):
模型对象名.updateMany(查找数据的条件, 新数据).then((data) => {
// 更新后的文档对象
console.log(data);
}).catch((err) => {
console.log('更新数据失败',err)
})
(3)完整的代码:
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 3、获取连接的实例
const db = mongoose.connection;
// 4、设置回调
db.once('open', () => {
let personType = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
sex: {
type: String,
enum: ['男', '女']
},
grade: {
type: String,
unique: true
},
hobby: Array
})
let person = mongoose.model('persons', personType)
// 更新数据
// updateData(person)
// 使用 `Promise` 语法更新数据
// 更新一条
// person.updateOne({sex: '女'}, {name: '小绿'}).then((data) => {
// 更新多条
person.updateMany({sex: '男'}, {name: '小哥'}).then((data) => {
// 更新后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('更新数据失败',err)
})
console.log('数据库连接成功')
})
// 使用 `async/await` 语法更新数据
async function updateData(person) {
try {
// 更新一条
// const user = await person.updateOne({sex: '女'}, {name: '小红'});
// 更新多条
const user = await person.updateMany({sex: '男'}, {name: '小华'});
// 更新后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('更新数据失败',err)
}
}
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
⑥ 查询文档:
(1)使用 async/await
语法查询数据:
a、查询一个文档(匹配的第一个):
async function findData(person) {
try {
const user = await person.findOne(查询的条件);
// 查询后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('查询数据失败',err)
}
}
b、根据_Id
查询文档(_id
是mongoose
自动生成的):
async function findData(person) {
try {
const user = await person.findById(_id的值);
// 查询后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('查询数据失败',err)
}
}
c、查询匹配的多个文档(匹配的所有的):
async function findData(person) {
try {
const user = await person.find(查询的条件);
// 查询后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('查询数据失败',err)
}
}
d、查询当前集合下的所有文档:
async function findData(person) {
try {
const user = await person.find();
// 查询后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('查询数据失败',err)
}
}
(2)使用 Promise
语法查询数据:
a、查询一个文档(匹配的第一个):
模型对象名.findOne(查找数据的条件).then((data) => {
// 查找的文档对象
console.log(data);
}).catch((err) => {
console.log('查找数据失败',err)
})
b、根据_Id
查询文档(_id
是mongoose
自动生成的):
模型对象名.findById(_id的值).then((data) => {
// 查找的文档对象
console.log(data);
}).catch((err) => {
console.log('查找数据失败',err)
})
c、查询匹配的多个文档(匹配的所有的):
模型对象名.find(_查询的条件).then((data) => {
// 查找的文档对象
console.log(data);
}).catch((err) => {
console.log('查找数据失败',err)
})
d、查询当前集合下的所有文档:
模型对象名.find().then((data) => {
// 查找的文档对象
console.log(data);
}).catch((err) => {
console.log('查找数据失败',err)
})
(3)完整的代码:
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 3、获取连接的实例
const db = mongoose.connection;
// 4、设置回调
db.once('open', () => {
let personType = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
sex: {
type: String,
enum: ['男', '女']
},
grade: {
type: String,
unique: true
},
hobby: Array
})
let person = mongoose.model('persons', personType)
// 查询数据
// findData(person)
// 使用 `Promise` 语法查询数据
// 查询一条
// person.findOne({sex: '女'}).then((data) => {
// 根据id查询
// person.findById('68491e76d4d339bb1ac779a9').then((data) => {
// 查询多条
// person.find({sex: '男'}).then((data) => {
// 查询所有数据
person.find().then((data) => {
// 查询后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('查询数据失败',err)
})
console.log('数据库连接成功')
})
// 使用 `async/await` 语法查询数据
async function findData(person) {
try {
// 查询一条
// const user = await person.findOne({sex: '女'});
// 根据id查询
// const user = await person.findById('68491e76d4d339bb1ac779a9');
// 查询多条
// const user = await person.find({sex: '男'});
// 查询所有数据
const user = await person.find();
// 查询后的文档对象
console.log(user);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
} catch (err) {
console.log('查询数据失败',err)
}
}
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
8、条件控制:
① 运算符:
(1)大于:$gt
(2)小于:$lt
(3)大于等于:$gte
(4)小于等于:$lte
(5)不恒等于:$ne
(6)使用语法:
{字段名: {运算符: 数值}}
(7)完整的代码:
查询
age
大于等于18,age
小于等于20 的数据
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 3、获取连接的实例
const db = mongoose.connection;
// 4、设置回调
db.once('open', () => {
let personType = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
sex: {
type: String,
enum: ['男', '女']
},
grade: {
type: String,
unique: true
},
hobby: Array
})
let person = mongoose.model('persons', personType)
// 使用 `Promise` 语法查询数据
person.find({
age: {
$gte: 18,
$lte: 20
}
}).then((data) => {
// 查询后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('查询数据失败',err)
})
console.log('数据库连接成功')
})
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
② 逻辑运算:
(1)逻辑或:$or
(2)逻辑与:$and
(3)使用语法:
{逻辑运算符: [条件1, 条件2, ...]}
(4)完整代码:
查询
age
大于等于18,age
小于等于20;name
是 小绿或者小哥 的数据
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 3、获取连接的实例
const db = mongoose.connection;
// 4、设置回调
db.once('open', () => {
let personType = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
sex: {
type: String,
enum: ['男', '女']
},
grade: {
type: String,
unique: true
},
hobby: Array
})
let person = mongoose.model('persons', personType)
// 使用 `Promise` 语法查询数据
person.find({
age: {
$gte: 18,
$lte: 20
},
$or: [{
name: '小绿'
}, {
name: '小哥'
}]
}).then((data) => {
// 查询后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('查询数据失败',err)
})
console.log('数据库连接成功')
})
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
③ 正则匹配:
(1)使用语法:
a、字面量形式:
{字段名: /正则语法/}
b、对象形式:
{字段名: new RegExp(正则语法)}
(2)完整代码:
查询
age
大于等于18,age
小于等于20;name
是 小绿或者小哥;grade
的值带有 二 的数据
// 1、引入mongoose
const mongoose = require('mongoose')
// 2、连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/a')
// 3、获取连接的实例
const db = mongoose.connection;
// 4、设置回调
db.once('open', () => {
let personType = new mongoose.Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
sex: {
type: String,
enum: ['男', '女']
},
grade: {
type: String,
unique: true
},
hobby: Array
})
let person = mongoose.model('persons', personType)
// 使用 `Promise` 语法查询数据
person.find({
age: {
$gte: 18,
$lte: 20
},
$or: [{
name: 'orange'
}, {
name: '小哥'
}],
// grade: /二/,
grade: new RegExp('二')
}).then((data) => {
// 查询后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('查询数据失败',err)
})
console.log('数据库连接成功')
})
db.on('error', () => {
console.log('数据库连接失败')
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
9、个性化读取:
exec()
函数:用于精确的控制查询的执行
① 字段筛选:select({字段名: 取值})
取值
0
:不需要的字段;取值1
:需要的字段
如果使用字段筛选,_id
默认是需要的字段,其它字段默认是不需要的字段
示例:返回当前集合中的name列表
person.find().select({name: 1, _id: 0}).then((data) => {
// 查询后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('查询数据失败',err)
})
② 数据排序:sort({字段名: 取值})
取值
1
:升序;取值-1
:倒序
如果使用字段筛选,_id
默认是需要的字段,其它字段默认是不需要的字段
示例:根据age进行从小到大排序,然后返回当前集合中的name列表
// 将查询和构建分离
letnames = person.find().select({name: 1, _id: 0})
names.sort({age: 1})
names.exec().then((data) => {
// 查询后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('查询数据失败',err)
})
③ 数据截取:
(1)限制返回数据的个数:limit(数量)
示例:根据age进行从小到大排序,然后返回当前集合中的前3位的name列表
person.find().select({name: 1, _id: 0}).sort({age: 1}).limit(3).exec().then((data) => {
// 查询后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('查询数据失败',err)
})
console.log('数据库连接成功')
(2)限制数据从第几个数据开始返回:skip(数量)
示例:根据age进行从小到大排序,然后跳过第一位,返回当前集合中的前3位的name列表
person.find().select({name: 1, _id: 0}).sort({age: 1}).skip(1).limit(3).then((data) => {
// 查询后的文档对象
console.log(data);
// 断开数据库连接。项目运行过程中,不会添加该代码
mongoose.disconnect()
}).catch((err) => {
console.log('查询数据失败',err)
})
10、代码模块化(CommonJs规范
):
① 初始的 index.js文件
:初始化
// 引入数据库连接处理
const db = require('./db/index.js')
const func = require('./model/index.js')
db.dbFunc(func.createPerson)
② 数据库 index.js文件
:数据库连接操作
// 数据库连接处理
const mongoose = require('mongoose')
const DBData = {
IP: '127.0.0.1',
PORT: '27017',
DBNAME: 'a'
}
mongoose.connect(`mongodb://${DBData.IP}:${DBData.PORT}/${DBData.DBNAME}`)
const db = mongoose.connection;
let dbFunc = function(success, error) {
if (typeof error !== 'function') {
error = () => { console.log('数据库连接失败') }
}
db.once('open', () => {
success()
})
db.on('error', () => {
error()
})
db.on('disconnected', () => {
console.log('数据库断开连接')
})
db.on('close', () => {
console.log('数据库关闭连接')
})
}
module.exports = {
dbFunc,
DBData
}
③ 模型库 schema.js文件
:定义结构对象
// 结构对象
const personType = {
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
sex: {
type: String,
enum: ['男', '女']
}
}
const bookType = {
title: {
type: String,
},
author: {
type: String,
default: '匿名',
},
}
module.exports = {
personType,
bookType
}
④ 模型库 index.js文件
:数据库连接成功的操作
let mongoose = require('mongoose')
const {personType} = require('./schema.js')
const createPerson = function() {
let personObj = new mongoose.Schema(personType)
let person = mongoose.model('persons', personObj)
person.create({
name: 'purple',
age: 25,
sex: '女'
}).then((data) => {
console.log('新增的数据', data)
mongoose.disconnect()
}).catch((err) => {
console.log('新增数据失败',err)
})
}
module.exports = {
createPerson
}
11、项目练习(自用):将本地数据库改为远程数据库
将 Express框架使用 中的 第七部分练习项目 进行修改
别忘记启动数据库服务器,该服务器与业务的服务器是两个东西!
① 进行数据库连接:
将原本的服务器代码封装为一个初始化的函数,用于进行数据库的连接(数据库连接成功后,才允许进行业务的服务连接)
www.js
文件代码如下:
// 引入数据库连接处理
const db = require('../db/index.js')
// 服务器初始化操作
let init = function() {
var app = require('../app');
var debug = require('debug')('13:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
}
db.dbFunc(() => {
// 先进行数据库的连接,然后再启动服务器
init()
})
② 进行结构对象的定义:
数据库服务器和业务服务器都连接成功后,开始对路由地址的数据进行处理
person.js
文件如下:
let mongoose = require('mongoose')
// 结构对象
const personType = {
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18,
},
email: {
type: String
}
}
let personObj = new mongoose.Schema(personType)
let person = mongoose.model('accounts', personObj)
module.exports = person
3、进行数据库的操作:
此时的路由,不仅对存储的数据进行处理,还对前端的页面进行处理(页面和数据共用一个路由)
index.js
文件如下:
var express = require('express');
var router = express.Router();
// 引入模型对象
const person = require('../model/person.js')
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
// 列表请求
router.get('/list', function(req, res, next) {
person.find().then((data) => {
res.render('list', {users: data});
}).catch((err) => {
res.end(err)
})
});
// 列表删除
router.get('/delete/:id', function(req, res, next) {
person.deleteOne({_id: req.params.id}).then((data) => {
res.redirect('/list')
}).catch((err) => {
res.end(err)
})
})
// 表单新增或者修改
router.get('/editForm', function(req, res, next) {
if(req.query.id){
person.find({_id: req.query.id}).then((data) => {
res.render('editForm', {user: data[0]});
}).catch((err) => {
res.end(err)
})
} else {
// 新增
res.render('editForm', {user: {}});
}
});
// 表单提交
router.post('/editForm', function(req, res, next) {
let editId = req.query.id
if(editId) {
person.updateOne({_id: editId}, {...req.body}).then((data) => {
res.redirect('/list')
}).catch((err) => {
res.end(err)
})
} else {
person.create({...req.body}).then((data) => {
res.redirect('/editForm')
}).catch((err) => {
res.end(err)
})
}
});
module.exports = router;
二、API
接口:
1、定义:
一个接口,就是服务中的一个路由规则,用来操作数据。
2、作用:
进行前后端的通信,可以让前端处理前端页面,后端只处理数据即可。
3、基本组成:
① 请求方法
② 请求地址
③ 请求参数
④ 响应结果
4、免费接口:
① 网站:
② 示例:
5、RESTful API
:
① 定义:
Web
服务接口的一种,是一种规范
② 编写接口注意:
(1)路径表示资源(数据库中的集合名称),不要有动词。
http://localhost:3000/list
√
http://localhost:3000/create
×
(2)操作和请求方法要对应
a、GET
:获取资源
b、POST
:创建资源
c、PUT
:更新整个资源
d、PATCH
:部分更新资源
e、DELETE
:删除资源
(3)操作和状态码要对应
6、json-server
:
① 定义:
快速搭建
RESTful API
服务
② 安装:
npm i json-server -g
③ 使用:
(1)新建一个 db.json
文件,初始化本地数据库内容:
{
"users": [
{
"id": 1,
"name": "张三"
},
{
"id": 2,
"name": "李四"
},
{
"id": 3,
"name": "王五"
}
]
}
(2)以 db.json
文件所在的文件夹作为工作目录,执行启动服务的命令:
json-server --watch db.json
(3)查看数据库中的数据:
默认端口是
3000
,即访问users
集合中的数据,需要访问http://127.0.0.1:3000/users
7、接口测试工具:
① apipost
:推荐使用
② postman
:不推荐(保存接口必须登录,登录费劲)
8、项目练习(自用):实现前端路由与后端路由分离
将 第一部分的
11、项目练习(自用):将本地数据库改为远程数据库
继续进行改造
① 新建一个 api
文件夹,用于进行后端路由(接口)的存储:
在该文件夹下新建 list.js
文件,用于编写与列表相关的后端接口
② 在 app.js
中引入后端路由文件,并且使用该文件:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
// 前端的页面路由
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
// 后端的服务api
var apiRouter = require('./routes/api/list')
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// 前端的页面路由
app.use('/', indexRouter);
app.use('/users', usersRouter);
// 后端的服务api
app.use('/api', apiRouter)
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
③ 在 list.js
中编写后接口:
// 根据api进行后端数据的处理
var express = require('express');
var router = express.Router();
// 引入模型对象
const person = require('../../model/person.js')
// 获取所有列表
router.get('/list', function(req, res, next) {
person.find().then((data) => {
res.json({
code: '0000',
msg: '列表请求成功',
data
})
}).catch((err) => {
res.json({
code: '1001',
msg: '列表请求失败',
data: err
})
})
});
// 获取单条数据
router.get('/list/:id', function(req, res, next) {
person.findById(req.params.id).then((data) => {
res.json({
code: '0000',
msg: '数据请求成功',
data
})
}).catch((err) => {
res.json({
code: '1002',
msg: '数据请求失败',
data: err
})
})
});
// 列表新增
router.post('/list', function(req, res, next) {
// 可以进行表单验证
person.create({...req.body}).then((data) => {
res.json({
code: '0000',
msg: '新增成功',
data
})
}).catch((err) => {
res.json({
code: '1003',
msg: '新增失败',
data: err
})
})
});
// 列表删除
router.delete('/list/:id', function(req, res, next) {
person.deleteOne({_id: req.params.id}).then((data) => {
res.json({
code: '0000',
msg: '删除成功',
data
})
}).catch((err) => {
res.json({
code: '1004',
msg: '删除失败',
data: err
})
})
})
// 列表修改
router.patch('/list/:id', function(req, res, next) {
// 可以进行表单验证
let editId = req.params.id
person.updateOne({_id: editId}, {...req.body}).then((data) => {
res.json({
code: '0000',
msg: '修改成功',
data
})
}).catch((err) => {
res.json({
code: '1005',
msg: '修改失败',
data: err
})
})
});
module.exports = router;