🍑 联合查询
在我们前端来说,会抽离一些公用组件。不会把重复的组件或者所有代码都放在一个文件夹下。对于后端来说,也是一样的, 我们不会把所有数据都放在一张表里,我们回进行分表,根据一些关联关系,进行联合查询
这样可以消除冗余,并且可以提高查询的效率
🥑 效果展示
tags 表中也多了对应的数据
🧐 分析
- 用户对于标签的关系 一个用户可以拥有多个标签
(一对多)
- 多个标签对应一个用户
(多对一)
🤔 用户表和标签表怎么做关联
操作数据库,使用typeorm,里面有两个装饰器
OneToMany
和ManyToOne
这两个装饰器就是做数据库关联关系
- tags.entity.ts
import { Column, Entity, PrimaryGeneratedColumn, BeforeInsert, CreateDateColumn, Generated, OneToOne, JoinColumn, ManyToOne } from 'typeorm'
import { User } from './user.entity'
@Entity()
export class Tags {
// 递增主键
@PrimaryGeneratedColumn()
id: number
@Column()
tags:string
// 多对一,回调函数,帮助Tags 表 和 User 表建立关联。第一个参数是User实体类, 第二个参数(回调函数)是关联的字段
@ManyToOne(()=>User,(user)=>user.tags)
@JoinColumn()
user:User
}
- user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
import { Tags } from './tags.entity';
// 表名
@Entity({ name: 'users' })
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 30, nullable: true, comment: 'user name' })
name: string;
@Column({ nullable: true, comment: 'user age' })
age: number;
@CreateDateColumn({ name: 'created_at', type: 'datetime', comment: 'created time' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at', type: 'datetime', comment: 'updated time' })
updatedAt: Date;
// 用户对标签事一对多关系,帮助User 表和 Tag 表建立关联。第一个参数事Tags 实体类,第二个参数(回调函数) 是关联的字段
@OneToMany(() => Tags, (tags) => tags.user)
tags:Tags[]
}
👱 前端部分逻辑
其实前端并不关心你是怎么关联的,我只调用相应的接口,传递相应的字段,后端做处理就行
//添加tag 接口
export const addTags = (data) => axios.post(`/user/add/tags`, data).then((res) => res.data)
// 模版显示
<el-dialog v-model="isShowTag" title="添加tag">
<el-select style="width: 100%" v-model="tags" multiple>
<el-option value="tag1">tag1</el-option>
<el-option value="tag2">tag2</el-option>
<el-option value="tag3">tag3</el-option>
</el-select>
<template #footer>
<el-button @click="addTa" type="primary">确定</el-button>
</template>
</el-dialog>
// js 接口调用
const addTa = async () => {
await addTags({
tags: tags.value,
userId: row.value.id
})
isShowTag.value = false
tags.value = []
init()
}
🧓 后端部分逻辑
💻 controller
- 前端是通过
user/add/tags
路由传递来的,那后端路由要做相应的匹配
- 前端会传来
tags 和 userId
,那controller 这一层要通过对应的装饰器来对参数进行解析
- 最后调用serveice 里的方法,并且传递解析完的参数,进行
对数据的操作
@Post('/add/tags')
addTags(@Body() params:{tags: string[], userId:number}) {
return this.userService.addTags(params);
}
💻 service
添加标签主要有这么几步
- 在service 定义 addTags方法
- 根据
用户id
,找到当前用户的信息
(因为要往指定用户下添加信息) - 将传递来的
tag 数据
,添加到Tag 表中
更新当前用户的数据到User表中
async addTags(params:{tags: string[], userId: number}){
// 根据id 找到当前用户信息
const userInfo = await this.usersRepository.findOne({where:{ id: params.userId}})
const tagList:Tags[] = []
// 通过循环,将tags 存入数据库
for (let i = 0; i < params.tags.length; i++) {
const T = new Tags()
T.tags = params.tags[i]
await this.tagsRepository.save(T)
tagList.push(T)
}
// 更新当前用户的tags
userInfo.tags = tagList
// 将当前用户更新的值,存入到数据库
return await this.usersRepository.save(userInfo)
}
关联查询,使用 relations
关键字,传入关联的表
即可
async findAll(query:{keyWord: string, page: number, pageSize: number }) {
const data = await this.usersRepository.find({
//查询的时候如果需要联合查询需要增加 relations
relations:['tags'],
where: {
name: Like(`%${query.keyWord}%`)
},
order: {
id: "DESC"
},
skip: (query.page - 1)* query.pageSize,
take: query.pageSize,
})
const total = await this.usersRepository.count({
where: {
name: Like(`%${query.keyWord}%`)
},
})
return {
data,
total
}
}
🎊 总结
- 对于联合查询,前端还是普通的传递参数,调用接口。这是后端做一个一个拆分。相当于前端拆组件,再拼接起来。
- 联合查询有很多关系,一对多,多对一,多对多,等等。主要实现是通过typeorm,里面的装饰器
OneToMany
和ManyToOne
, ManyToMany 具体可参考TypeORM 关系这一章 https://typeorm.bootcss.com/relations - 表关联完毕,就是数据怎么做关联
- 根据id,找到对应的用户。
- 根据传递来的tag,依次添加到tag 表中
- 更新当前用户的值
- 查询时 如果需要 联合查询需要增加
relations:['tags']
即可,代表关联查询那张表
🏠 项目地址
-
Vue 前端地址:
https://gitee.com/Big_Cat-AK-47/vue-project -
nest 后端地址:https://gitee.com/Big_Cat-AK-47/nest
🎉 Nest 系列 往期文章
1. 《Nest系列 - 1. 🔥运行一个Nest项目以及整体目录学习》
2. 《Nest系列 - 2. 🔥Nest 代码生成器,让你告别base代码书写!!!》
3. 《 Nest系列 - 3. 🔥掌握常见Nest 装饰器,奠定坚实基础!!!!!!》
4. 《Nest系列 - 4. 🔥听说人人都会CRUD,可是我还不会怎么办???-《 4.1-数据库连接和实体》》
5. # 《Nest系列 - 4. 🔥听说人人都会CRUD,可是我还不会怎么办???-《4.2结合前端使用实现CRUD》