오늘도 Promise.all과 map의 중첩이 된 코드를 리팩토링 하였다.
await Promise.all(
memberQuery.map(async (member) => {
const qqq = Array.from({ length: monthStartToEnd.length }, () => []);
await Promise.all(
organizationId.map(async (organizationId) => {
await Promise.all(
monthStartToEnd.map(async (date, i) => {
const start = new Date(date);
const copyDate = new Date(date);
const end = new Date(copyDate.setDate(copyDate.getDate() + 1));
const aaa = await this.workCheckRepository
.createQueryBuilder('WorkCheck')
.leftJoinAndSelect('WorkCheck.member', 'member')
.leftJoinAndSelect('WorkCheck.company', 'company')
.leftJoinAndSelect('WorkCheck.organization', 'organization')
.leftJoinAndSelect('WorkCheck.schedule', 'schedule')
.leftJoinAndSelect('WorkCheck.roleCategory', 'roleCategory')
.where('WorkCheck.member = :memberId', {
memberId: member.id,
})
.andWhere('WorkCheck.organization = :organizationId', {
organizationId,
})
.andWhere(
`WorkCheck.workDay BETWEEN '${start.toISOString()}' AND '${end.toISOString()}'`,
)
.orderBy('WorkCheck.workDay', 'ASC')
.addOrderBy('member.name', 'ASC')
.getMany();
aaa.length !== 0 ? (qqq[i] = aaa) : false;
}),
);
}),
);
qqq.flat(2).length !== 0 ? result2.push(qqq) : false;
}),
);
위 의 코드는 오늘 날짜를 기준으로 해당 월의 조회 결과를 반환하는 로직이다.
이 로직도 Promise.all과 map이 중첩되어 있으며 qqq라는 변수에 Array.from을 통해 해당 월의 날짜만큼 길이의 배열을 생성해주며, 조건에 맞는 결과들을 qqq라는 변수에 넣어주다 보니 데이터가 적은데도 조회하는데 시간이 오래걸리는 문제점이 있었다.
await Promise.all(
memberInOrg.map(async (member) => {
const workChecks = await this.workCheckRepository
.createQueryBuilder('WorkCheck')
.leftJoinAndSelect('WorkCheck.company', 'company')
.leftJoinAndSelect('WorkCheck.member', 'member')
.leftJoinAndSelect('WorkCheck.organization', 'organization')
.leftJoinAndSelect('WorkCheck.schedule', 'schuedule')
.leftJoinAndSelect('WorkCheck.roleCategory', 'roleCategory')
.where('WorkCheck.member = :memberId', { memberId: member.id })
.andWhere(
'DATE(WorkCheck.workDay) BETWEEN DATE(:start) AND DATE(:end)',
{
start: monthStartToEnd[0],
end: monthStartToEnd[monthStartToEnd.length - 1],
},
)
.orderBy('WorkCheck.workday', 'ASC')
.addOrderBy('member.name', 'ASC')
.getMany();
const memberWorkCheck = [];
monthStartToEnd.forEach((workDay, i) => {
const workChecksForDay = workChecks.filter(
(workCheck) => workCheck.workDay.getDate() === workDay.getDate(),
);
memberWorkCheck[i] = [...workChecksForDay];
});
const temp = {
member,
data: memberWorkCheck,
};
result.push(temp);
}),
);
위의 코드로 리팩토링을 진행하였는데 위의 코드에서는 생략되었지만 먼저 member의 저장소에서 조건에 맞는 member들을 미리 조회하는 로직을 만들었고 map을 돌면서 조건에 맞는 결과들을 새로운 배열에 담아주었다.
중첩됐던 코드가 하나로 줄었으며, 조회 속도 또한 이전 코드 보다 훨씬 빨라 졌다.
아직 부족한 점이 많은 리팩토링 코드지만 나의 원래 코드보다 빨라졌다는 점에서 칭찬을 주고싶다.
새로 배운점 : 쿼리빌더의 andWhere 조건에서 DATE, BETWEEN으로 검색하게 되면 시간이 아닌 날짜로 비교를 하기 때문에 MySQL에서의 저장되는 시간과 서버의 시간이 맞지 않아 조회안되던 결과도 조회된다는 점을 알게되었다.