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();