You need to enable JavaScript to run this app. TypeORM关联查询:获取用户工单最新交互及交互用户类型
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 15:45:07