축구팀 관리 프로젝트 26일차 - 경기장 조회 페이지네이션 적용
전날 경기장 데이터를 새로 Mysql에 저장하는 작업을 했습니다. 전국 경기장 데이터가 담긴 csv 파일을 파싱해서 Mysql에 넣었는데 데이터량이 필터를 했음에도 10,000건이 넘어갔습니다. 그래서 경기장 조회 화면에 페이지네이션을 적용하였습니다.
경기장 조회 화면 페이지네이션 적용
이전 경기장 조회 화면은 다음과 같았습니다. 기존에 있던 자료에는 경기장 목록이 50건 이하였습니다. 하지만 전날 작업한 csv 파일 안에 있는 경기장 목록은 3만건 정도가 있었습니다.
* 파싱한 전국 경기장 데이터가 담긴 csv 파일
경기장 정보를 담는 테이블이 location과 soccer_fields가 있는데 아래 깃허브 프로젝트에 있는 파일로 csv 파싱 작업을 하고 나니 테이블에 만건이 넘어가게 되었습니다. 그 상태로 경기장 조회하게되니 만건 넘는 경기장을 한번에 조회하는 문제가 발생했습니다.
SELECT
SUM(soccer_fields) AS soccer_fields,
SUM(location_cnt) AS location_cnt
FROM (
SELECT
COUNT(*) AS soccer_fields,
0 AS location_cnt
FROM
test17.soccer_fields
UNION ALL
SELECT
0 AS soccer_fields,
COUNT(*) AS location_cnt
FROM
test17.location
) AS cnt;
경기장 조회 페이지네이션 적용
경기장 조회화면에서 디폴트로 전체 조회되어 조회 속도가 느려지는 점을 잡기 위해 화면에 페이지네이션을 적용하기로 했습니다.
먼저 경기장 조회 API 부터 수정했습니다. 컨트롤러 에서 화면 입력 받은 페이지정보를 서비스단으로 보내주고,
// soccerfield.controller.ts
/**
* 경기장 전체 조회
* @param req
* @returns
*/
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('page')
async findAllStadium(@Request() req, @Query() dto: PaginateFieldDto) {
const userId = req.user.id;
const data = await this.soccerfieldService.findAllStadium(userId, dto, dto.name);
return data;
}
서비스 페이지에서 해당 페이지 정보를 바탕으로 페이지별 조회 결과를 return하는 작업을 해줍니다.
// soccerfield.service.ts
/**
* 경기장 전체 조회
* @returns
*/
async findAllStadium(userId: number, dto: PaginateFieldDto, name?: string) {
const options: FindManyOptions<SoccerField> = {
relations: {
locationfield: true,
}
};
if (name) {
options.where = { field_name: Like(`%${name}%`) };
}
if (!options) {
throw new NotFoundException('등록된 경기장 목록이 없습니다.');
}
//return soccerField;
return await this.commonService.paginate(dto, this.soccerFieldRepository, options, 'soccerfield');
}
백엔드는 위와 같이 수정하고 프론트엔드 수정을 위해 리엑트에서는 아래와 같이 처음 페이지 로드시 page를 1로 고정하여 조회를 하도록 하였고,
// pages/match/index.tsx
useEffect(() => {
const accessToken = localStorage.getItem("accessToken");
const findAllSoccerField = async (page: number = 1) => {
try {
let apiUrl = `${process.env.REACT_APP_SERVER_HOST}:${
process.env.REACT_APP_SERVER_PORT || 3000
}/api/soccerfield/page/?page=${page}`;
// 검색어가 있는 경우 검색 쿼리 추가
if (searchQuery.trim() !== "") {
apiUrl += `&name=${searchQuery}`;
}
const response = await axios.get(apiUrl,
{
headers: {
Authorization: `Bearer ${accessToken}`, // Bearer 토큰 추가
},
withCredentials: true,
}
);
const fieldData = response.data.data;
setField(fieldData); // creatorId가 존재하면 구단주로 간주
setTotal(response.data.total);
setLoading(false); // 데이터 로딩 완료
} catch (error) {
console.error("데이터 불러오기 실패:", error);
setLoading(false); // 데이터 로딩 실패
setTotal(0);
}
};
findAllSoccerField(); // 데이터를 불러오는 함수 호출
}, []);
페이지 변동시 아래 이벤트가 동작하도록 하였습니다.
// pages/match/index.tsx
const changePage = async (page: number) => {
try {
const accessToken = localStorage.getItem("accessToken");
const response = await axios.get(
`${process.env.REACT_APP_SERVER_HOST}:${
process.env.REACT_APP_SERVER_PORT || 3000
}/api/soccerfield/page/?page=${page || 1}&name=${searchQuery}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
withCredentials: true,
}
);
const fieldData = response.data.data;
setField(fieldData); // creatorId가 존재하면 구단주로 간주
setTotal(response.data.total);
} catch (error) {
console.error("멤버 정보를 불러오는 데 실패했습니다.", error);
}
};
▼ 이전 진행한 프로젝트들 ▼
'내일배움캠프 > 축구팀 관리 프로젝트' 카테고리의 다른 글
축구팀 관리 프로젝트 33일차 - 프로젝트 유저 테스트 준비 (0) | 2024.02.13 |
---|---|
축구팀 관리 프로젝트 27일차 - 경기 생성 및 결과 테스트 코드 작성 (0) | 2024.02.08 |
축구팀 관리 프로젝트 25일차 - 2월부터 AWS Public IPv4 요금 부과 (0) | 2024.02.05 |
축구팀 관리 프로젝트 24일차 - 포메이션 추천 시나리오 작성 (1) | 2024.02.05 |
축구팀 관리 프로젝트 23일차 - 리엑트 반응형으로 화면 비율 고정 (0) | 2024.02.04 |