3년 전 저는 각 지자체에서 제공하는 공공시설 위치 CSV를 받아 보고 깜짝 놀랐습니다. 컬럼 이름은 제각각이고 좌표는 WGS84와 TM 좌표가 뒤섞여 있었죠. 게다가 사용자 제보로 들어오는 위치는 주소도, 위도·경도도 빠져 있는 경우가 많아 결국 지도에 찍을 수가 없었습니다. "이걸 누가 다 정리해?" 싶은 순간이었는데, 결국 제가 했습니다. 비슷한 데이터 정제 지옥을 겪고 있다면 그때의 삽질 기록이 도움이 될지도 모르겠습니다.
DocumentPicker + FileSystem 조합으로 충분했습니다. 당시에 다뤘던 행 수가 1,700건 수준이라 굳이 서버를 거치지 않아도 됐습니다.react-native-csv를 사용했습니다. PapaParse API와 같아서 온보딩 비용이 거의 없었습니다.관리자 메뉴에 BatchUpload 스크린을 추가했습니다. 파일을 고르면 CSV를 파싱하고 LocationInfo 배열로 만들어 넘깁니다.
// screens/Developer/BatchUpload.tsx
const result = readString(string, {
header: true,
dynamicTyping: true,
skipEmptyLines: true,
});
const locationsInfo = dataArray
.filter((data) => data.latitude && data.longitude)
.map((data) => ({
title: data.title,
address: data.location,
latlng: {
latitude: Number(data.latitude),
longitude: Number(data.longitude),
},
}));
CSV 헤더를 강제로 맞춰야 해서, 각 지자체 데이터는 미리 스크립트로 컬럼명을 통일한 뒤 업로드했습니다. 그래도 한 번씩 콤마가 들어간 메모 때문에 파서가 깨지곤 해서, 문제 파일은 "로 감싸도록 사전에 규칙을 정했습니다.
데이터마다 "실내/실외", "공공기관/공공시설"처럼 표현이 제각각이라 문자열을 Enum으로 바꾸는 헬퍼를 만들어 썼습니다.
// utils/utils.ts
export const convertStringToPlaceType = (placeType: string) => {
switch (placeType) {
case "공공기관":
return PlaceType.publicInstitution;
// ...중략
default:
return PlaceType.etc;
}
};
이 덕분에 필터링 로직이나 클러스터 색상 변경 조건이 훨씬 간단해졌습니다. 말미에 공백이나 특수 문자가 섞인 경우가 많아서 업로드 직전에 트리밍을 의무화했습니다.
CSV로 만든 데이터를 Firestore에 쓰는 로직은 batchUploadLocationInfo가 담당했습니다.
// firebase/locationHandler.ts
const { ok: isAdmin } = await checkAdmin(currentUser);
if (!isAdmin) return { ok: false, error: "운영진만 대량 업로드" };
const { ok, data } = await uploadAdminLocationInfo(locationInfo, currentUser);
여기서 uploadAdminLocationInfo는 기존 위치 반경 5m 내에 중복이 있는지 검사한 뒤 active를 true로 설정합니다. 공공 데이터만 1,700건이 넘다 보니 비슷한 좌표가 많았고, 이 검사를 빼면 똑같은 위치가 여러 번 등록될 위험이 컸습니다.
사용자가 제보할 때는 지도에서 포인트만 찍도록 했습니다. 위도·경도를 받은 뒤 바로 latLngtoAddressAPI로 주소를 보강했습니다.
// utils/api.ts
const response = await fetch(
`${gcUrl}coords=${latLng.longitude},${latLng.latitude}&sourcecrs=epsg:4326&orders=roadaddr&output=json`,
{
headers: {
"X-NCP-APIGW-API-KEY-ID": clientId,
"X-NCP-APIGW-API-KEY": clientSecret,
},
}
);
예상 못 한 문제는 공공 데이터 좌표와 사용자가 찍은 좌표가 5~10m 정도 오차가 날 때가 있다는 겁니다. 반경 5m 중복 검사에 계속 걸려서, 좌표를 소수점 6자리로 반올림해 비교했고 필요한 경우에는 관리자 화면에서 수동 병합 기능을 추가했습니다.
keepAwake 옵션으로 화면이 꺼지지 않도록 했습니다.최종적으로 정제한 공공기관 위치 데이터는 약 1,700건, 사용자 제보는 200건 정도였고 모두 Firestore에 안정적으로 안착했습니다. 덕분에 데이터 정제에 쓰던 시간이 하루에 30분 이하로 줄었고, 제보 승인 속도도 크게 빨라졌어요. 3년이 지난 지금은 데이터 포맷이나 API 정책이 조금씩 바뀌었지만, "업로드 파이프라인을 먼저 자동화하자"는 교훈은 여전히 유효합니다. 여러분은 지리 데이터 정제에서 어떤 함정을 만났었나요? 댓글로 서로의 삽질을 공유해요!