我们常常有这样的要求, 一篇文章, 里面有一个一对多的关联关系记录. 如果我们要在一个列表里, 对多篇文章, 以最新的一条记录做排序.
打个例子, 一项目, 多人同时开发, 每次推送, 都添加一条信息. 要做列表展示时, 只显示每个人的最近一条记录.
js
// 项目
@Entity("project")
export class Project {
@Column()
id: number;
@CreateDateColumn({ comment: "创建时间", name: 'create_at', nullable: true })
createAt?: Date
// 一对多的关系
@OneToMany(() => Process, process => process.component)
processes: Process[];
// 最新的一条进展, 映射使用
newestProcess?: Process;
}
// 添加进展记录
@Entity("process")
export class Process {
@Column()
id: number;
@CreateDateColumn({ comment: "创建时间", name: 'create_at', nullable: true })
createAt?: Date
// 多对一的关系
@ManyToOne(() => Project, project => project.processes)
@JoinColumn({name : "project_id"})
project: Project;
}
一般操作, 不以 processes 做排序的情况可做.
上面二个表, 直接关联查找出所以有的数据, processes 数组查出来后, 在计算最新一条, 通过模型转换成需要的列表.
js
const result = await this.componentRepo.createQueryBuilder('project')
.leftJoinAndSelect('project.processes', 'processes')
.getMany()
得到 result 后, 我们在对 processes 去排序, 取得最新一条. 但是, 这里有个问题, 不能用 process 的 createAt 去排序, 数据会不准
优秀操作, 可以对 processes 里面字段做排序
同样的操作, 多了一步映射一条数据. 把 processes 最新的一条映射到外面 Project 去
在实体表 Project 添加上
js
// 最新的一条进展, 映射使用
newestProcess?: Process;
然后,
js
const result = await this.componentRepo.createQueryBuilder('project')
.leftJoin('project.processes', 'processes') // 不需要全部数据, 可以用 leftJoin
.leftJoinAndMapOne('project.newestProcess', Process, 'newestProcess', 'newestProcess.create_at = (SELECT MAX(p.create_at) FROM processes p WHERE p.projectt_id = project.id)') // 映射最新一条进展
.orderBy("newestProcess.createAt", "DESC") // 这里排序
.getMany()
上面 leftJoinAndMapOne 条件的原理是, 查到 processes 里面 create_at 时间是最大的一条记录, 然后给到 newestProcess.create_at.
PS: 就这一条映射, typeorm 官方文档真没有啊, 翻了几遍内外网, 都没有找到方法, 我一开始是第一种方法来做的, 后面发现排序有问题, 一直找解决方法都没有找到, 最后查看源码, 发现 leftJoinAndMapOne 可以上 sql 原始语法, 后面 sql 的原始语法来做了. 尝试了不知道多少次了, 一次次改 sql, 出错了也不显示, 一次次请求数据, 最后成功了, 感慨万千啊.