地理空間クエリでレストランを探す
Overview
MongoDB の地理空間インデックスを使用すると、地理空間の形状とポイントを含むコレクションに対して空間クエリを効率的に実行できます。 このチュートリアルでは、地理空間機能の機能を紹介し、さまざまなアプローチを比較するために、単純な地理空間アプリケーションのクエリを作成するプロセスについて説明します。
このチュートリアルでは、地理空間インデックスの概念を簡単に紹介し、$geoWithin
、$geoIntersects
、$nearSphere
. を使用してその使用方法を説明します。
ユーザーがニューヨーク市内のレストランを見つけるのに役立つモバイル アプリケーションを設計しているとします。アプリケーションは、次の条件を満たす必要があります。
$geoIntersects
, を使用してユーザーの現在の近所を特定すること$geoWithin
を使用して、その地域のレストランの数を表示すること
このチュートリアルでは、2dsphere
インデックスを使用して、球面形状上のこのデータを照会します。
球面および平面形状について詳しくは、「地理空間モデル」を参照してください。
ディストーション
球面形状は、地球などの 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 にいるとします。現在の近隣地域を見つけるには、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" }
近隣のレストランをすべて検索
特定の地域に含まれるすべてのレストランを検索するクエリを実行することもできます。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
は、ドキュメントを特定の順序で返さないため、ユーザーには最も遠いドキュメントが最初に表示される可能性があります。
次のようにすると、ユーザーから 5 マイル以内にあるすべてのレストランが検索されます。
db.restaurants.find({ location: { $geoWithin: { $centerSphere: [ [ -73.93414657, 40.82302903 ], 5 / 3963.2 ] } } })
$centerSphere
の 2 番目の引数はラジアン単位の半径を受け入れるため、それをマイル単位の地球の半径で割る必要があります。 距離単位の変換の詳細については、「球面ジオメトリを使用した距離の計算」を参照してください。
次のコードを使用して並び替えしました: $nearSphere
$nearSphere
を使用して、$maxDistance
の期間をメートル単位で指定することもできます。これにより、ユーザーから 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 } } })