이전에는 두 테이블을 조인하는 쿼리가 필요한 경우 queryBuilder를 사용했었는데, ORM을 더 효과적으로 사용하기 위해 기본적인 find 메서드에서 사용할 수 있는 옵션들 중 조인과 관련있는 내용들을 정리해보았다.
https://typeorm.io/find-options
select
옵션
/**
* Specifies what columns should be retrieved.
*/
select?: FindOptionsSelect<Entity> | FindOptionsSelectByString<Entity>;
relations
옵션
/**
* Indicates what relations of entity should be loaded (simplified left join form).
*/
relations?: FindOptionsRelations<Entity> | FindOptionsRelationByString;
where
옵션
/**
* Simple condition that should be applied to match entities.
*/
where?: FindOptionsWhere<Entity>[] | FindOptionsWhere<Entity>;
일부 칼럼만 조회할 때 사용한다.
const projects = await this.projectRepository.find({
**select: { id: true, title: true, subject: true, created_at: true }**,
where: { projectToMember: { member: { id: member.id } } },
});
쿼리를 살펴본 결과 select 옵션에 포함되지 않은 updated_at 칼럼 값은 SELECT하지 않는 것을 알 수 있었다.
조인하는 상대 테이블의 칼럼도 명시할 수 있다.
const projects = await this.projectRepository.find({
select: {
id: true, // project 테이블의 id 칼럼
title: true,
subject: true,
created_at: true,
**projectToMember: { id: true }, // project_to_member 테이블의 id 칼럼**
},
where: { projectToMember: { member: { id: member.id } } },
});
다음과 같이 사용하면 조인하는 상대 테이블의 정보를 모두 가져올 수 있다.
const projects = await this.projectRepository.find({
where: { projectToMember: { member: { id: member.id } } },
**relations: { projectToMember: true }**,
});
쿼리에서 project 테이블 뿐만 아니라 project_to_member 테이블의 칼럼도 모두 SELECT한다.
추후 project_to_member에서 회원의 프로젝트 롤(role)을 조회할 때 쓰면 유용할 것 같다.
const projects = await this.projectRepository.find({
select: {
id: true,
title: true,
subject: true,
created_at: true,
**projectToMember: { role: true },**
},
where: { projectToMember: { member: { id: member.id } } },
**relations: { projectToMember: true },** // relations 부분이 없어도 쿼리는 동일, 다만 project_to_member 테이블과 조인하는 점을 명확히 알 수 있도록 명시하기로 결정
});
SELECT `project`.`id` AS `Project_id`,
`project`.`title` AS `Project_title`,
`project`.`subject` AS `Project_subject`,
`project`.`created_at` AS `Project_created_at`,
`project`.`updated_at` AS `Project_updated_at`,
`Project__Project_projectToMember`.`id` AS
`Project__Project_projectToMember_id`,
`Project__Project_projectToMember`.`created_at` AS
`Project__Project_projectToMember_created_at`,
`Project__Project_projectToMember`.`updated_at` AS
`Project__Project_projectToMember_updated_at`,
`Project__Project_projectToMember`.`project_id` AS
`Project__Project_projectToMember_project_id`,
`Project__Project_projectToMember`.`member_id` AS
`Project__Project_projectToMember_member_id`
FROM `project` `Project`
LEFT JOIN `project_to_member` `Project__Project_projectToMember`
ON `Project__Project_projectToMember`.`project_id` =
`project`.`id`
LEFT JOIN `member` `121c70d2eeb042e9de57100ccc9660eeffb2727d`
ON
`121c70d2eeb042e9de57100ccc9660eeffb2727d`.`id` = `Project__Project_projectToMember`.`member_id`
WHERE (((((( `121c70d2eeb042e9de57100ccc9660eeffb2727d`.`id` = ? )))))) -- PARAMETERS: [1484]
SELECT `project`.`id` AS `Project_id`,
`project`.`title` AS `Project_title`,
`project`.`subject` AS `Project_subject`,
`project`.`created_at` AS `Project_created_at`,
`project`.`updated_at` AS `Project_updated_at`
FROM `project` `Project`
LEFT JOIN `project_to_member` `Project__Project_projectToMember`
ON `Project__Project_projectToMember`.`project_id` =
`project`.`id`
LEFT JOIN `member` `121c70d2eeb042e9de57100ccc9660eeffb2727d`
ON
`121c70d2eeb042e9de57100ccc9660eeffb2727d`.`id` = `Project__Project_projectToMember`.`member_id`
WHERE (((((( `121c70d2eeb042e9de57100ccc9660eeffb2727d`.`id` = ? ))))))
필요한 일부 칼럼만 SELECT해서 조회하면 쿼리를 줄일 수 있지만, 아래와 같이 일부 칼럼만 SELECT 하는 것은 특정 API에 최적화된 쿼리일 수 있다는 생각이 들었다.
getProjectList(member: Member): Promise<Project[]> {
return this.projectRepository.find({
select: { id: true, title: true, subject: true, created_at: true },
where: { projectToMember: { member: { id: member.id } } },
relations: { projectToMember: true },
});
}
따라서 레포지토리에서는 아래와 같이 범용적으로 사용할 수 있는 데이터 액세스 메서드를 만들어 사용하다가 추후 특정 API에서 성능 문제가 발생하면 쿼리를 튜닝하기로 결정했다.
getProjectList(member: Member): Promise<Project[]> {
return this.projectRepository.find({
where: { projectToMember: { member: { id: member.id } } },
relations: { projectToMember: true },
});
}