여려가지 서비스에서 위치기반 서비스를 제공한다. 이것이 잘 작동하기 위해서는 먼저 점, 선, 공간(면)과 같은 지도에서 쓰일 수 있는 정보들이 데이터베이스에 잘 담겨 있어야 한다. 또한 이렇게 잘 저장되어 있는 정보를 상황에 맞게 활용할 수 있어야 한다. 그래서 일반적인 데이터를 저장하는 것과 달리 공간에 대한 정보를 저장하기 위해 공간 데이터베이스가 필요하다.
일반적으로 사용되는 공간 데이터 타입은 아래의 그림과 같은 종류들이 있다.
공간데이터 타입 | 정의 | sql |
---|---|---|
Point | 좌표 공간에서 한 지점의 위치를 표시 | POINT (5 5) |
LineString | 다수의 Point를 연결해주는 선분 | LINESTRING (5 5, 20 22, 15 17) |
Polygon | 다수의 선분들이 연결되어 닫혀 있는 상태인 다각형 | POLYGON ((5 5, 10 30, 20 55, 20 10, 5 5)) |
Multi-Point | 다수 개의 Point 집합 | MULTIPOINT (5 5, 30 20, 33 45) |
Multi-LineString | 다수 개의 LineString 집합 | MULTILINESTRING ((10 10, 20 20), (20 15, 30 40)) |
Multi-Polygon | 다수 개의 Polygon 집합 | MULTIPOLYGON (((5 5, 10 30, 20 55, 20 10, 5 5)) , (( 40 25, 44 40, 57 35, 25 10, 40 25 ))) |
GeomCollection | 모든 공간 데이터들의 집합 | GEOMETRYCOLLECTION ( POINT (10 10), LINESTRING (20 20, 30 40), POINT (30 15) ) |
과제에서는 Polygon으로 저장되어 있는 지역의 데이터가 있었다. 그리고 위도와 경도로 표시된 사용자의 위치정보(Point)를 받아서 지역(데이터로서 Polygon)내부에 있는지 혹은 외부에 있는지 판단이 필요했다. 이를 위해서는 단순히 데이터들로만은 알 수 없고, 이를 판단해줄 공간관계 함수가 필요하다. 이를 구현하기 위해 작성했던 코드는 다음과 같다.
async findAreaByLatAndLng(lat: string, lng: string): Promise<Area> {
const foundArea = await this.manager.query(`
select * from area where ST_Contains(area.area_boundary, ST_GeomFromText('POINT(${parseFloat(
lat,
)} ${parseFloat(lng)})'));
`);
/*
ST_Contains은 공간 관계 함수.
Polygon타입으로 저장되어 있는 area.area_boundary에
사용자의 위치가 포함 되어 있는지 여부를 Boolean값으로 리턴한다.
*/
return foundArea;
}
과제에서 사용자가 지역으로부터 벗어났을 경우, 벌금을 부과해야한다. 그런데 이를 구현하기가 쉽지 않아 Polygon의 중심점으로부터 사용자의 거리를 피타고라스를 써서 구했다. 하지만 과제를 제출 한 후, 이를 계산할 수 있는 공간 관계 함수가 있다는 것을 알게 되었다.
async findDistance(lat: string, lng: string) {
const distance = await this.manager.query(`select ST_Distance(ST_GeomFromText('POLYGON ((-90 180, 0 180, 0 16.34, -90 180))'),ST_GeomFromText('POINT(0 190)'));
`);
/*ST_Distance는 공간 데이터 사입 간의 거리를 구해주는 함수이다.
Polygon타입과 Point타입 간의 거리를 구해준 것이다.
*/
return distance
}