※ MongoDB 공식 매뉴얼에 나와있는 Find Restaurants with Geospatial Queries (예제 - 공간쿼리를 사용한 레스토랑 찾기) 부분을 번역해 보도록 하겠습니다. 번역을 안하는게 나을 것 같은 용어들은 한번만 번역하거나 그대로 두었습니다.
Overview
MongoDB 의 geospatial 인덱싱은 GeoJSON 객체 타입으로 구성된 콜렉션에 효율적으로 공간쿼리를 실행할 수 있도록 해줍니다. 이 튜토리얼은 간단한 geospatial 어플리케이션에서 쿼리 작성 과정을 통해 geospatial feature 의 기능들을 소개하고 다른 접근법들을 비교합니다.
이 튜토리얼은 geospatial index 의 개념에 대해 간단히 소개하고, $geoWithin / $geoIntersects / $nearSphere 에서의 사용법을 보여줄 것입니다.
뉴욕시에 있는 레스토랑들을 유저들이 찾을 수 있게 도와주는 mobile 어플리케이션을 디자인한다고 가정해 봅시다. 이 어플리케이션은 :
- $geoIntersects 를 사용해 유저의 현재 지역을 결정해야 합니다.
- $geoWithin 을 사용해 그 지역에 있는 레스토랑의 개수를 보여줘야합니다.
- $nearSphere 을 사용해 유저로부터 지정된 거리 내에 있는 레스토랑들을 찾아야 합니다.
이 튜토리얼에서는 2dsphere index 를 사용해 spherical geometry 에서 데이터를 쿼리할 것입니다.
Geospatial Models 이 링크를 통해 spherical & flat geometries 에 대한 더 많은 정보를 확인할 수 있습니다.
Distortion (왜곡)
지도를 시각화할 때 spherical geometry 는 왜곡되서 보여지는데, 이는 지구와 같은 3차원 구체를 평평한 평면에 투사해야 하는 점 때문입니다.
예를 들어 경도 위도 포인트 - (0,0) / (80,0) / (80,80) / (0,80) - 로 정의된 구형 사각형 스펙을 보면, 아래 그림과 같은 영역이 표시 될 것입니다.
Searching for Restaurants (레스토랑 검색)
Prerequisites (전제조건)
- https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json
- https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json
위의 두개 링크에서 데이터셋 예제를 다운받으세요. 여기엔 각각의 레스토랑과 지역 콜렉션이 포함되어 있습니다.
다운로드 한 데이터셋을 데이터베이스로 임포트 하십시오 :
mongoimport <path to restaurants.json> -c=restaurants
mongoimport <path to neighborhoods.json> -c=neighborhoods
geospatial index 는 거의 늘 $geoWithin 과 $geoIntersects 쿼리 성능을 향상 시킵니다.
지리학적인 데이터이기 때문에 mongo shell 을 사용하여 각 콜렉션에 2dsphere index 를 생성합니다 :
db.restaurants.createIndex({ location: "2dsphere" })
db.neighborhoods.createIndex({ geometry: "2dsphere" })
Exploring the Data (데이터 살펴보기)
mongo shell 안에서 새로 생성된 레스토랑 콜렉션을 조회해보세요 :
db.restaurants.findOne()
이 쿼리는 다음과 같은 document 를 반환할 것입니다 :
{
location: {
type: "Point",
coordinates: [-73.856077, 40.848447]
},
name: "Morris Park Bake Shop"
}
이 레스토랑 document 는 다음 그림에서 보여지는 위치와 일치합니다 :
튜토리얼에서 2dsphere index 를 사용하기때문에, geometry data 의 location 필드는 반드시 GeoJSON 포맷을 따라야 합니다.
이제 지역 콜렉션을 보겠습니다 :
db.neighborhoods.findOne()
이 쿼리는 다음과 같은 document 를 반환할 것입니다 :
{
geometry: {
type: "Polygon",
coordinates: [[
[ -73.99, 40.75 ],
...
[ -73.98, 40.76 ],
[ -73.99, 40.75 ]
]]
},
name: "Hell's Kitchen"
}
반환된 geometry 는 다음 그림에서 그려진 지역과 일치합니다 :
Find the Current Neighborhood (현재 지역 찾기)
유저의 모바일 기기가 꽤 정확한 유저 위치를 줄 수 있다고 가정하면, $geoIntersects 를 사용해 유저의 현재 지역을 찾는것은 간단합니다.
유저가 -73.93414657 (경도), 40.82302903 위도에 위치해있다고 생각해 봅시다. 현재 지역을 찾기위해선, GeoJSON 포맷의 $geometry 필드를 사용해서 포인트를 명시해야 합니다.
db.neighborhoods.findOne({ geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } })
이 쿼리는 다음과 같은 결과를 반환합니다 :
{
"_id" : ObjectId("55cb9c666c522cafdb053a68"),
"geometry" : {
"type" : "Polygon",
"coordinates" : [
[
[
-73.93383000695911,
40.81949109558767
],
...
]
]
},
"name" : "Central Harlem North-Polo Grounds"
}
Find all Restaurants in the Neighborhood (지역 내의 모든 레스토랑 찾기)
주어진 지역내에 있는 모든 레스토랑을 찾는 쿼리 또한 가능합니다. 다음의 쿼리들은 유저를 포함한 지역을 찾은 후에 그 지역내의 레스토랑 수를 카운팅합니다 :
var neighborhood = db.neighborhoods.findOne( { geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] } } } } )
db.restaurants.find( { location: { $geoWithin: { $geometry: neighborhood.geometry } } } ).count()
이 쿼리는 아래 시각화된 그림에서 볼 수 있듯이 요청된 지역내에 127개의 레스토랑이 있다는 것을 보여줍니다 :
Find Restaurants within a Distance (거리 내에 있는 레스토랑 찾기)
점으로부터 명시된 거리 내의 모든 레스토랑을 찾기 위해선, $geoWithin 과 $centerSphere 을 모두 사용해 정렬되지 않은 결과값을 받거나, 거리값으로 정렬된 결과를 원한다면 $nearSphere 과 $maxDistance 를 사용해야 합니다.
Unsorted with $geoWithin ($geoWithin 을 사용한 정렬되지 않은 결과값)
원형의 지역내에 모든 레스토랑을 찾기 위해선, $geoWithin 과 $centerSphere 를 모두 사용해야 합니다. $centerSphere 은 중심점과 라디안을 이용한 반지름 지정을 통해 원형 지역을 나타내는 MongoDB 만의 특별한 문법입니다.
$geoWithin 은 정렬된 형태로 document 를 반환하지 않습니다. 따라서 유저 기준 가장 먼 document 가 제일 처음에 보여질 수도 있습니다.
다음은 유저로부터 5마일 내에 있는 모든 레스토랑을 찾는 쿼리입니다 :
db.restaurants.find({ location:
{ $geoWithin:
{ $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })
$centerSphere 의 두번째 인자로 라디안을 이용한 반지름 값을 받기 때문에, 지구의 반지름으로 해당 마일 값을 나눠줘야 합니다.
거리 단위에 대한 변환 정보는 Calculate Distance Using Spherical Geometry 이 링크에서 볼 수 있습니다.
Sorted with $nearSphere ($nearSphere 을 사용한 정렬된 결과값)
또한 미터단위로 $maxDistance 를 명시해 $nearSphere 을 사용할 수도 있습니다. 다음은 유저 기준 5마일 내의 모든 레스토랑을 가까운 것에서 먼 순서로 정렬된 결과값을 받는 쿼리입니다 :
var METERS_PER_MILE = 1609.34
db.restaurants.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }, $maxDistance: 5 * METERS_PER_MILE } } })
출처 : https://docs.mongodb.com/manual/tutorial/geospatial-tutorial/
'Database > mongoDB' 카테고리의 다른 글
$geoWithin (0) | 2020.03.31 |
---|---|
$geoIntersects (0) | 2020.03.25 |
Geospatial Query Operators (Geospatial 쿼리 연산자) (0) | 2020.03.25 |
GeoJSON Objects (GeoJSON 객체) (0) | 2020.03.18 |
MongoDB - Geospatial Queries (지리공간 쿼리) (0) | 2020.03.02 |