지리 공간적 쿼리로 식당 찾기
개요
MongoDB의 지리 공간적 인덱싱을 사용하면 지리 공간적 형태와 점이 포함된 컬렉션에서 공간 쿼리를 효율적으로 실행할 수 있습니다. 이 튜로리얼에서는 지리 공간적 기능의 역량을 제시하고 다양한 접근 방식을 비교하기 위해 간단한 지리 공간 애플리케이션 쿼리를 작성하는 프로세스를 안내합니다.
이 튜토리얼은 지리 공간적 인덱스의 개념을 간략하게 소개한 다음 $geoWithin
, $geoIntersects
및 $nearSphere
로 사용하는 방법을 선보입니다.
사용자가 뉴욕에서 레스토랑을 찾는 과정을 지원하는 모바일 애플리케이션을 디자인한다고 가정해 보겠습니다. 애플리케이션은 다음을 충족해야 합니다.
$geoIntersects
를 사용하여 사용자의 현재 주변 환경을 파악합니다.$geoWithin
을 사용하여 주변의 레스토랑 수를 표시하고$nearSphere
를사용하여 지정된 거리 내에 있는 레스토랑을 찾습니다.
이 튜토리얼은 2dsphere
인덱스를 사용하여 구형 기하학에서 이 데이터를 쿼리합니다.
구형 및 평면 도형에 대한 자세한 정보는 Geospatial Models에서 확인 가능합니다.
왜곡
구형 기하학은 지구와 같은 3차원 구를 평면에 투영하는 속성 때문에 지도에 시각화될 때 왜곡을 유발합니다.
예를 들어, 경도 위도 점 (0,0)
, (80,0)
, (80,80)
및 (0,80)
으로 정의된 구형 정사각형 사양을 사용합니다. 다음 그림은 이 리전에 해당하는 영역을 묘사합니다.
레스토랑 검색
전제 조건
https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/neighborhoods.json 및 https://raw.githubusercontent.com/mongodb/docs-assets/geospatial/restaurants.json 에서 예시 데이터베이스를 다운로드할 수 있습니다. 여기에는 restaurants
및 neighborhoods
컬렉션이 각각 포함되어 있습니다.
데이터세트를 다운로드한 후 데이터베이스로 가져옵니다.
mongoimport <path to restaurants.json> -c=restaurants mongoimport <path to neighborhoods.json> -c=neighborhoods
지리 공간적 인덱스이며 거의 항상 $geoWithin
및 $geoIntersects
쿼리의 성능 향상에 기여합니다.
이 데이터는 지리적 데이터이므로 mongosh
를 사용하여 각 컬렉션에 2dsphere
인덱스를 생성합니다.
db.restaurants.createIndex({ location: "2dsphere" }) db.neighborhoods.createIndex({ geometry: "2dsphere" })
데이터 탐색
mongosh
에서 새로 만든 restaurants
컬렉션의 항목을 검사합니다.
db.restaurants.findOne()
이 쿼리는 다음과 같은 문서를 반환합니다.
{ location: { type: "Point", coordinates: [-73.856077, 40.848447] }, name: "Morris Park Bake Shop" }
이 레스토랑 문서는 다음 그림에 표시된 위치에 해당합니다.
이 튜토리얼은 2dsphere
인덱스를 사용하므로 location
필드의 기하학 데이터는 GeoJSON 형식을 준수해야 합니다.
이제 neighborhoods
컬렉션의 항목을 검사합니다.
db.neighborhoods.findOne()
이 쿼리는 다음과 같은 문서를 반환합니다.
{ geometry: { type: "Polygon", coordinates: [[ [ -73.99, 40.75 ], ... [ -73.98, 40.76 ], [ -73.99, 40.75 ] ]] }, name: "Hell's Kitchen" }
이 지오메트리는 다음 그림에 표시된 리전에 해당합니다.
현재 주변 지역 찾기
사용자의 모바일 디바이스가 사용자의 위치를 상당히 정확하게 파악할 수 있다고 가정하면 $geoIntersects
를 통해 사용자의 현재 주변 지역을 간단히 찾을 수 있습니다.
사용자가 경도 -73.93414657, 위도 40.82302903에 있다고 가정합니다. 현재 주변 지역을 찾으려면 특수 $geometry
필드를 사용하여 GeoJSON 형식으로 포인트를 지정합니다.
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" }
주변 레스토랑 모두 찾기
특정 지역에 포함된 레스토랑을 모두 찾기 위한 쿼리도 수행할 수 있습니다. mongosh
에서 다음을 실행하여 사용자가 위치한 지역을 찾은 다음 해당 지역 내의 레스토랑 수를 계산합니다.
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개의 레스토랑이 있음을 알려주며 다음 그림에 시각화되어 있습니다.
일정 거리 이내 레스토랑 찾기
한 포인트에서 지정된 거리 내에 있는 레스토랑을 찾으려면 $geoWithin
및 $centerSphere
를 사용하여 정렬되지 않은 순서로 결과를 반환하거나, 거리별로 정렬된 결과가 필요한 경우 $nearSphere
및 $maxDistance
를 사용할 수 있습니다.
정렬되지 않음 $geoWithin
원형 리전에서 레스토랑을 찾으려면 $geoWithin
을 $centerSphere
와 함께 사용합니다. $centerSphere
는 중심과 반지름을 라디안 단위로 지정하여 원형 리전을 나타내는 MongoDB 전용 구문입니다.
$geoWithin
는 문서를 특정 순서대로 반환하지 않으므로 사용자에게 가장 먼 문서를 먼저 표시할 수 있습니다.
다음은 사용자로부터 약5km 이내에 있는 모든 레스토랑을 찾습니다.
db.restaurants.find({ location: { $geoWithin: { $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })
$centerSphere
의 두 번째 인수는 라디안 단위의 반지름을 허용하므로 이를 킬로미터 단위의 지구 반지름으로 나눠야 합니다. 거리 단위 간 변환에 대한 자세한 내용은 구형 연산자 거리를 라디안으로 변환하기에서 확인 가능합니다.
정렬됨 $nearSphere
$nearSphere
를 사용하고 $maxDistance
텀을 미터 단위로 지정할 수도 있습니다. 이렇게 하면 사용자로부터 8km 이내에 있는 모든 식당이 가장 가까운 순서대로 정렬되어 반환됩니다.
var METERS_PER_MILE = 1609.34 db.restaurants.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [ -73.93414657, 40.82302903 ] }, $maxDistance: 5 * METERS_PER_MILE } } })