写完用户模块、会议室模块、预定模块之后,就只剩下统计模块了,这节我们就来写下这个模块。
这个模块只有 2 个统计的功能:
分别是统计会议室的使用频率、用户的预定频率:
没有新的实体,只是对已有数据的统计。
在 echarts 官网可以看到柱形图和饼图都只需要一个二维的数据,也就是 [[a, b], [a, b], [a, b]] 这样的形式的数据:
我们先在数据库里写下这个 sql:
select u.username 用户名, count(*) 预定次数
from booking b
left join users u
on b.userId = u.id
where b.startTime between '2023-09-24' and '2023-09-30'
group by b.userId;
关联 users 和 booking 表,过滤出在这段日期内的预定记录,根据用户分组,统计每组的预定数量。
这样查询出来的就是这段时间内每个用户预定了多少次会议室。
同理,也可以很轻松的统计处会议室被预定的频率:
select m.name 会议室名字, count(*) 预定次数
from booking b
left join meeting_room m
on b.roomId = m.id
where b.startTime between '2023-09-24' and '2023-09-30'
group by b.roomId;
把关联的表换成 meeting_room 就好了。
当然,现在的数据不是很多,我们添加一些数据:
直接通过 mysql workbench 的 copy row 和 paste row 快速复制一些数据就好了。
复制出来的数据要改下 id,以及其他一些信息。
我添加了 4 条数据,并且指定了不同的 userId 和 roomId,点击 apply 应用修改。
然后再跑下那两个统计 sql
没啥问题。
接下来在 nest 里把这个统计 sql 实现就好了。
nest g module statistic
生成一个新的 module。
nest g service statistic
nest g controller statistic
之后生成 controller 和 service。
然后在 service 里实现下上面两个统计。
import { Injectable } from '@nestjs/common';
import { InjectEntityManager } from '@nestjs/typeorm';
import { Booking } from 'src/booking/entities/booking.entity';
import { User } from 'src/user/entities/user.entity';
import { EntityManager } from 'typeorm';
@Injectable()
export class StatisticService {
@InjectEntityManager()
private entityManager: EntityManager;
async userBookingCount() {
const res = await this.entityManager
.createQueryBuilder(Booking, 'b')
.select('u.id', '用户id')
.addSelect('u.username', '用户名')
.leftJoin(User, 'u', 'b.userId = u.id')
.addSelect('count(1)', '预定次数')
.where('b.startTime between :time1 and :time2', {
time1: '2023-09-24',
time2: '2023-09-30'
})
.addGroupBy('b.user')
.getRawMany();
return res;
}
async meetingRoomUsedCount() {
}
}
注入 entityManager 来查询。
统计相关的 sql 比较复杂,我们使用 queryBuilder 的 api。
queryBuilder 的 api 和写 sql 的体验差不多。
我们用 repl 的方式跑下试试:
npm run repl
await get(StatisticService).userBookingCount()
仔细观察下这个打印的 sql,其实和我们前面在 mysql workbench 里写的是一样的。
用 typeorm 的 query buidler 的 api 可以写各种 sql。
然后我们加上参数,并且改下别名:
async userBookingCount(startTime: string, endTime: string) {
const res = await this.entityManager
.createQueryBuilder(Booking, 'b')
.select('u.id', 'userId')
.addSelect('u.username', 'username')
.leftJoin(User, 'u', 'b.userId = u.id')
.addSelect('count(1)', 'bookingCount')
.where('b.startTime between :time1 and :time2', {
time1: startTime,
time2: endTime
})
.addGroupBy('b.user')
.getRawMany();
return res;
}
再跑下:
await get(StatisticService).userBookingCount('2023-09-23', '2023-09-30')
没啥问题。
然后在 controller 里加个接口:
import { Controller, Get, Inject, Query } from '@nestjs/common';
import { StatisticService } from './statistic.service';
@Controller('statistic')
export class StatisticController {
@Inject(StatisticService)
private statisticService: StatisticService;
@Get('userBookingCount')
async userBookignCount(@Query('startTime') startTime: string, @Query('endTime') endTime) {
return this.statisticService.userBookingCount(startTime, endTime);
}
}
把 repl 的模式停掉,重新跑服务:
npm run start:dev
用 postman 访问下:
http://localhost:3005/statistic/userBookingCount?startTime=2023-09-23&endTime=2023-09-30
可以看到,返回了这段时间的统计数据。
这样,加个 echarts 就可以实现饼图、柱形图了:
然后,我们再写另一个接口。
和用户预定次数的统计差不多:
async meetingRoomUsedCount(startTime: string, endTime: string) {
const res = await this.entityManager
.createQueryBuilder(Booking, 'b')
.select('m.id', 'meetingRoomId')
.addSelect('m.name', 'meetingRoomName')
.leftJoin(MeetingRoom, 'm', 'b.roomId = m.id')
.addSelect('count(1)', 'usedCount')
.where('b.startTime between :time1 and :time2', {
time1: startTime,
time2: endTime
})
.addGroupBy('b.roomId')
.getRawMany();
return res;
}
上面是 service 部分。
然后是 controller:
@Get('meetingRoomUsedCount')
async meetingRoomUsedCount(@Query('startTime') startTime: string, @Query('endTime') endTime) {
return this.statisticService.meetingRoomUsedCount(startTime, endTime);
}
postman 里测试下:
http://localhost:3005/statistic/meetingRoomUsedCount?startTime=2023-09-23&endTime=2023-09-30
也没啥问题,和我们在 mysql workbench 里自己写 sql 统计的结果一样。
这样,统计模块的后端部分就完成了。
代码在小册仓库。
总结
这节我们实现了统计模块的后端代码。
就两个统计 sql,我们先在 mysql workbench 里写了这个统计 sql,然后在 typeorm 里用 query builder 的方式实现。
query builder 的 api 和直接写 sql 差不多。
前端部分拿到统计的数据,就可以用 echarts 展示饼图或者柱形图了。