How to get latest chat message from each user in TypeORM?

Viewed 143

I am using Nest.js backend and using TypeORM for the Mysql query. My MySQL query is

let qry = `select chats.id, chats.senderId, chats.receiverId, chats.message, chats.messageType, users.fullName from chats inner join (select max(id) as maxid from chats where chats.senderId = ${req.user.sub} OR chats.receiverId = ${req.user.sub} group By (if(senderId > receiverId, senderId, receiverId)), (if(senderId > receiverId,  receiverId, senderId))) t1 on chats.id=t1.maxid join users users ON users.id = (CASE WHEN chats.senderId = ${req.user.sub} THEN chats.receiverId ELSE chats.senderId END)`;
let result = await entityManager.query(qry);

But I want to write this query using TypeORM. There are two tables chats and users. The Entity for these tables are:

Structure of ChatEntity

import { Entity, Column, PrimaryGeneratedColumn, JoinColumn, OneToOne, ManyToOne } from 'typeorm';
import { UserEntity } from "./user.entity";

enum MessageType {
  TEXT = 'text',
  MEDIA = 'media',
}

@Entity('chats')
export class ChatEntity  {
  @PrimaryGeneratedColumn()
  id: number;

    @Column()
    senderId: number;                 

  @Column()
  receiverId: number;

    @Column({ type: "longtext", nullable: true })
  message: string; 

    @Column({ type: 'enum', enum: MessageType, default: 'text' })
    messageType: string;

    @Column({ default: false })
  isGroup: boolean; 

    @Column({ default: false })
  isRead: boolean; 

    @Column({ type: "timestamp", default: () => "CURRENT_TIMESTAMP" })
  createdAt: Date;
    
    @Column({ type: "timestamp", default: () => "CURRENT_TIMESTAMP", onUpdate: "CURRENT_TIMESTAMP"})
  updatedAt: Date;

    @ManyToOne(() => UserEntity, user => user.sentMessages)
    @JoinColumn({ name: "senderId" }) 
    sender: UserEntity;

    @ManyToOne(() => UserEntity, user => user.receivedMessages)
    @JoinColumn({ name: "receiverId" }) 
    receiver: UserEntity;

}

Structure of UserEntity

import { Entity, Column, Index, PrimaryGeneratedColumn,JoinColumn, OneToMany } from 'typeorm';
import { ChatEntity } from "./chat.entity";

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

    @Column()
    roleId: number;                 

  @Column()
  firstName: string;

  @Column()
  lastName: string;

    @Column()
  fullName: string;

    @Column({unique: true})
  email: string;

    @Column({ default: false })
  emailVerified: boolean;

    @Column({ select: false })
  password: string;

    @Column({ type: "timestamp", default: () => "CURRENT_TIMESTAMP" })
  createdAt: Date;
    
    @Column({ type: "timestamp", default: () => "CURRENT_TIMESTAMP", onUpdate: "CURRENT_TIMESTAMP"})
  updatedAt: Date;

    @OneToMany(() => ChatEntity, chat => chat.sender)
    @JoinColumn() 
    sentMessages: ChatEntity;

    @OneToMany(() => ChatEntity, chat => chat.receiver)
    @JoinColumn() 
    receivedMessages: ChatEntity;

}

I tried several methods but was not able to generate this query in TypeORM. Please, anybody, suggest the right TypeORM query.

Finally, after spending 1 day I am able to make a query with TypeORM. I am writing my own solution.


        const query = this.chatRepo.createQueryBuilder('chats')
        query.select(['chats.id', 'chats.senderId', 'chats.receiverId', 'chats.message', 'chats.messageType'])
        query.innerJoin(subQuery => {
                return subQuery
                        .select("MAX(id)", "maxId")
                        .from(ChatEntity, "chats")
                        .where(new Brackets(sq => {
                            sq.where("senderId = :senderId", { senderId: +req.user.sub })
                                .orWhere("receiverId = :receiverId", { receiverId:+req.user.sub })
                        }))     
                        .groupBy("LEAST(senderId, receiverId)")
                        .addGroupBy("GREATEST(senderId, receiverId)")                                           
        }, "subQ", 'chats.id = subQ.maxId')
        query.innerJoinAndSelect('chats.sender', 'sender')
        query.innerJoinAndSelect('chats.receiver', 'receiver')
        query.orderBy('chats.id', 'DESC');
        let notifications = await query.getMany();

0 Answers
Related