✅오늘 학습 Keyword
2023.06.01 - [실전프로젝트] - 230601 실전프로젝트6 [Node.js/Nest.js 공공 data저장, 좌표주입하기]
230601 실전프로젝트6 [Node.js/Nest.js 공공 data저장, 좌표주입하기]
✅오늘학습 Keyword 1. postgreSQL-RDS 연결 2. 대용량 csv data 저장 ✅local data와 카카오맵API 연동하기 - 겪은 문제 1. 저번 포스팅에서 기록했듯 대용량 data의 좌표를 부여하는 작업에서, 쿼터 문제가 발
veritas-crystal.tistory.com
✅오늘 겪은 문제
1. 프로젝트에 쓰일 최종적인 data인 csv파일에 카카오좌표를 크롤링하고 있었다.
이 과정에서 지번주소, 도로명주소가 둘 다 카카오맵 api에 등록되지 않은 경우 좌표를 불러올 수 없는 경우가 20만건이나 발생했다. 20만건의 공공데이터를 그대로 손실하는 것은 매우 큰 손해라 생각하여 해결 방법을 생각해봤다. 좌표를 불러오지 못한 상점들의 주소는 ~~번지, 101, 102호, 지상1층 등 카카오맵 api에 정식으로 등록되있지 않은 경우가 많았고 그런 경우에는 상점의 이름으로 찾은 후 해당 좌표를 받아오는 것으로 코드를 수정했다. 코드를 수정하니 좌표들이 잘 불러와졌다~~~~이로써 더 많은 데이터를 보유할 수 있게 됌!
#repository
async getCoordinate(storeNmae: string, address: string): Promise<any> {
try {
if (!address && !storeNmae) {
return null;
}
const query = address ? address : storeNmae;
const encodedQuery = encodeURIComponent(query);
const url = `https://dapi.kakao.com/v2/local/search/address.json?query=${encodedQuery}`;
// const restApiKey = '800b8fe2427efbffbef3bc6fe96a5464';
const restApiKey = `${process.env.KAKAO_REST_API_KEY}`;
const headers = { Authorization: 'KakaoAK ' + restApiKey };
const response = await axios.get(url, { headers });
const result = response.data;
if (result.documents.length !== 0) {
const resultAddress = result.documents[0].address;
const coordinates = [resultAddress.y, resultAddress.x];
return coordinates;
} else {
return null;
}
} catch (error) {
throw new Error(
'Error fetching coordinates from Kakao API: ' + error.message,
);
}
}
//저장
async updateCoord(lat: number, lon: number, storeId: number): Promise<any> {
await this.stores.update(storeId, { lat, lon });
}
#service
async updateCoordinates(): Promise<void> {
try {
const stores = await this.storesRepository.getStoreAddressId();
for (const store of stores) {
const { newAddress, storeName, oldAddress, storeId } = store;
try {
let coordinates = await this.storesRepository.getCoordinate(
null,
newAddress,
);
if (!coordinates) {
coordinates = await this.storesRepository.getCoordinate(
null,
oldAddress,
);
}
if (!coordinates) {
coordinates = await this.storesRepository.getCoordinate(
storeName,
null,
);
}
if (!coordinates) continue;
//La = y, Ma = x
const lat = coordinates[0];
const lon = coordinates[1];
await this.storesRepository.updateCoord(lat, lon, storeId);
console.log(
`Updated coordinates for address: ${storeId},${storeName},${newAddress}${lat}, ${lon}`,
);
} catch (error) {
console.error(
`Error updating coordinates for address: ${storeId},${storeName},${newAddress}, ${oldAddress}`,
error,
);
}
}
} catch (error) {
console.error('Error occurred during database operation:', error);
}
}
2. 사용자 위치를 기반으로 주변 식당을 탐색하는 api에서 식당 data에 rating, currentwaiting 까지 잘 추가 되었다.
하지만 sort된 결과가 빈 배열로 출력되는 에러가 있었다.
//주변식당탐색
async searchRestaurants(
southWestLatitude: number,
southWestLongitude: number,
northEastLatitude: number,
northEastLongitude: number,
sortBy?: 'distance' | 'name' | 'waitingCnt' | 'waitingCnt2' | 'rating',
): Promise<{ 근처식당목록: searchRestaurantsDto[] }> {
const restaurants = await this.storesRepository.findAll();
const restaurantsWithinRadius = restaurants.filter((restaurant) => {
const withinLatitudeRange =
Number(restaurant.lat) >= southWestLatitude &&
Number(restaurant.lat) <= northEastLatitude;
const withinLongitudeRange =
Number(restaurant.lon) >= southWestLongitude &&
Number(restaurant.lon) <= northEastLongitude;
return withinLatitudeRange && withinLongitudeRange;
});
console.log(restaurantsWithinRadius);
// 거리 계산 로직
const calculateDistance = (
source: { latitude: number; longitude: number },
target: { latitude: number; longitude: number },
): number => {
const latDiff = Math.abs(source.latitude - target.latitude);
const lngDiff = Math.abs(source.longitude - target.longitude);
const approximateDistance = Math.floor(
latDiff * 111000 + lngDiff * 111000,
);
return approximateDistance;
};
//user위치에 따른 거리값을 모든 sort조건에 포함시켜준다
//calculateDistance로 얻은 distance 값을 출력값에 포함시켜준다
const userLocation = {
latitude: southWestLatitude,
longitude: southWestLongitude,
};
const restaurantsResult: searchRestaurantsDto[] = [];
restaurantsWithinRadius.forEach(async (restaurant) => {
const distance = calculateDistance(userLocation, {
latitude: Number(restaurant.lat),
longitude: Number(restaurant.lon),
});
const storesHashes = await this.redisClient.hgetall(
`store:${restaurant.storeId}`,
);
let currentWaitingCnt: string;
let rating: string;
if (!storesHashes.currentWaitingCnt) {
currentWaitingCnt = '0';
rating = '0';
}
restaurantsResult.push({
...restaurant,
distance: distance,
currentWaitingCnt: Number(currentWaitingCnt),
rating: Number(rating),
});
console.log(
restaurantsResult,
'restaurants에 currentwaitingCnt, rating 적용하여 출력 준비됌',
);
});
//정렬로직모음
restaurantsResult.sort((a, b) => {
if (sortBy === 'distance') {
return (a.distance || 0) - (b.distance || 0);
} else if (sortBy === 'name') {
return a.storeName.toUpperCase() < b.storeName.toUpperCase() ? -1 : 1;
} else if (sortBy === 'waitingCnt') {
return a.currentWaitingCnt - b.currentWaitingCnt;
} else if (sortBy === 'waitingCnt2') {
return b.currentWaitingCnt - a.currentWaitingCnt;
}
return 0;
});
console.log(restaurantsResult);
return { 근처식당목록: restaurantsResult };
}
위 코드에서 restaurantsResult.push 작업을 거친 restaurantsResult까지는 콘솔에 잘 찍히는 것을 확인했는데,
콘솔에 찍히는 data가 무한대로 반복되어 찍히고 있었다. 이 부분에서 비동기 문제와 관련있지 않을까 추측함.
✅오늘 알게된 점 및 추후 학습 계획
잠결에 이 문제를 생각하다가 불현듯 스친 생각이라 진짜 눈 뜨자마자 코드짰다.
뭔가 생각나면 바로바로 적용해봐야겠다.
'개발 > 프로젝트-식당 웨이팅 앱 FOOD LINE' 카테고리의 다른 글
230626 실전프로젝트22 [Nest.js] Jmeter로 부하테스트하기3 (0) | 2023.06.28 |
---|---|
Docker / CICD 란? (0) | 2023.06.23 |
230622 실전프로젝트20 [Nest.js] Jest로 Unit test code 짜기2 (0) | 2023.06.23 |
230621 실전프로젝트19 [Nest.js] Jest로 Unit test code 짜기 (0) | 2023.06.21 |
230620 실전프로젝트18 [Nest.js] Jmeter로 부하테스트하기2 (0) | 2023.06.20 |