TypeORM关联查询:获取用户工单最新交互及交互用户类型
TypeORM 指定用户工单最新交互查询实现
前置实体命名修正
先统一实体关联命名,否则查询会出现字段找不到、关联为空的问题:
- 统一关联字段名,删除葡语/中文混用命名:将
TicketInteraction中反向关联ticket的字段名改为interactions,匹配Ticket中定义的interactions字段 - 统一操作用户字段名:将
TicketInteraction中操作用户字段统一为user,替换现有混用的usuario - 统一实体类名:将
User.ts中导出的类名从Usuario改为User,匹配其他实体的导入命名 - 修正导入路径:将
User.ts中Gym的导入路径从./Academia改为./Gym - 统一字段命名:不要混用
name/nome这类同义词,全表字段命名保持一致
实现思路
- 先通过条件匹配过滤出指定用户的所有工单
- 不直接全量关联交互记录(避免返回所有历史交互),先通过子查询/窗口函数拿到每个工单对应的最新交互ID(按
date+time倒序排序取第一条) - 逐层关联最新交互对应的操作用户、操作用户绑定的
UserType
通用兼容版查询代码(适配所有数据库)
// 替换为实际需要查询的目标用户ID const targetUserId = 'xxx-xxx-xxx-xxx'; // 子查询:匹配当前工单下最新的交互记录ID const latestInteractionSubQuery = createQueryBuilder() .subQuery() .select('ticket_interaction.id') .from(TicketInteraction, 'ticket_interaction') .where('ticket_interaction.ticket = ticket.id') .orderBy('ticket_interaction.date', 'DESC') .addOrderBy('ticket_interaction.time', 'DESC') .limit(1) .getQuery(); // 主查询组装数据 const ticketList = await createQueryBuilder(Ticket, 'ticket') // 过滤指定用户的工单 .where('ticket.user.id = :targetUserId', { targetUserId }) // 仅关联匹配到的最新单条交互 .leftJoinAndSelect( 'ticket.interactions', 'interaction', `interaction.id = ${latestInteractionSubQuery}` ) // 关联交互的操作用户 .leftJoinAndSelect('interaction.user', 'operator') // 关联操作用户的类型 .leftJoinAndSelect('operator.type', 'user_type') .orderBy('ticket.id', 'ASC') .getMany();
高效版查询代码(适配支持窗口函数的数据库:MySQL 8.0+、PostgreSQL 8.4+)
如果使用的数据库支持窗口函数,可大幅减少查询次数,效率更高:
const targetUserId = 'xxx-xxx-xxx-xxx'; const ticketList = await createQueryBuilder(Ticket, 'ticket') .where('ticket.user.id = :targetUserId', { targetUserId }) // 用窗口函数批量计算所有工单的最新交互 .leftJoin( (qb) => qb .select('ti.*') .from(TicketInteraction, 'ti') // 按工单分组,按时间倒序排序后取第一条 .addSelect( 'ROW_NUMBER() OVER (PARTITION BY ti.ticket_id ORDER BY ti.date DESC, ti.time DESC)', 'row_num' ) .where('row_num = 1'), 'interaction', 'interaction.ticket_id = ticket.id' ) .leftJoinAndSelect('interaction.user', 'operator') .leftJoinAndSelect('operator.type', 'user_type') .getMany();
返回结构示例
[ { "id": "0b8c5b62-1eb2-4b28-9fb9-97dc680a3c02", "title": "工单标题", "interactions": [ { "id": "1e0bc060-ceb7-4722-898a-9bb22685afd0", "description": "最新交互内容", "date": "2021-03-07", "time": "18:45:52", "user": { "id": "0739f286-ecf5-4579-8efe-3062941a5e7f", "name": "操作用户名", "type": { "id": "xxx-xxx-xxx-xxx", "description": "用户类型(如管理员/普通用户)" } } } ] } ]
注意:如果希望返回的交互不是数组格式,可在查询中通过
.addSelect将交互字段单独映射为工单的直接属性,无需修改实体结构即可实现。
内容的提问来源于stack exchange,提问作者Ban
相关产品推荐
相关产品推荐

