You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NestJS+TypeORM中按用户最后发送消息时间排序用户

问题描述

基于NestJS、TypeORM和PostgreSQL开发应用时,需获取按用户最后发送消息时间戳排序的用户列表。已定义User和Message实体,数据表记录及期望结果如下,尝试的查询代码报错,寻求正确实现方案。

实体定义

user.entity.ts

import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Message } from './message.entity';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @OneToMany(() => Message, (message) => message.user)
  messages: Message[];
}

message.entity.ts

import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn } from 'typeorm';
import { User } from './user.entity';

@Entity('messages')
export class Message {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  userId: number;

  @Column()
  message: string;

  @CreateDateColumn({ type: 'timestamp' })
  created: Date;

  @ManyToOne(() => User, (user) => user.messages)
  user: User;
}

数据表记录

Users表

idname
1John
2Mike
3Norman

Messages表

iduserIdmessagecreated
13Hello there2024-08-21 05:30:00
22Hi!2024-08-22 06:40:00
33Hello again2024-08-23 07:50:00

期望结果

[
  {
    "id": 3,
    "name": "Norman"
  },
  {
    "id": 2,
    "name": "Mike"
  },
  {
    "id": 1,
    "name": "John"
  }
]

尝试的查询及报错

this.userRepository
  .createQueryBuilder('user')
  .leftJoinAndSelect('user.messages', 'message')
  .groupBy('user.id')
  .addGroupBy('user.name')
  .orderBy('MAX(message.created)', 'DESC')
  .getMany();

报错信息:

"MAX(message" alias was not found. Maybe you forgot to join it?
解决方案

方案1:子查询获取用户最后消息时间(性能更优)

无需关联所有消息记录,适合数据量较大的场景:

this.userRepository
  .createQueryBuilder('user')
  .leftJoin(
    (qb) => qb
      .select('userId', 'userId')
      .addSelect('MAX(created)', 'lastMessageTime')
      .from(Message, 'message')
      .groupBy('userId'),
    'userLastMessage',
    'user.id = userLastMessage.userId'
  )
  .orderBy('userLastMessage.lastMessageTime', 'DESC', 'NULLS LAST')
  .select(['user.id', 'user.name'])
  .getMany();

NULLS LAST配置确保无消息的用户排在末尾,匹配示例中John的排序位置。

方案2:主查询添加MAX字段别名

若需同时获取用户最后消息时间,可采用此方式:

this.userRepository
  .createQueryBuilder('user')
  .leftJoin('user.messages', 'message')
  .groupBy('user.id')
  .addGroupBy('user.name')
  .addSelect('MAX(message.created)', 'lastMessageTime')
  .orderBy('lastMessageTime', 'DESC', 'NULLS LAST')
  .select(['user.id', 'user.name'])
  .getMany();

通过addSelect为聚合结果设置别名,避免TypeORM解析MAX(message.created)时出现错误。

内容的提问来源于stack exchange,提问作者StormTrooper

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 11:33:12