🐙
【MongoDB】aggregateのクエリで「$geoNear」を使用して指定した地点から近いドキュメントを取得
概要
MongoDBではMongoDBの地理空間インデックスの記事で紹介されている通り、緯度・経度をデータに登録することで、位置情報を利用した検索クエリが可能となります。今回はaggregateのクエリで地理情報を使用した集計$geoNearの機能を使ってみたので、メモ書きです。
前提
- 使用したMongoDBのバージョンは
v8.0.1です。 - Pythonのmongoengineを使用してクエリを発行しています。
$geoNearについて
$geoNear(集計)のドキュメントに記載の通り、使用にあたりいくつか留意点があります。個人的に注意が必要かなと感じた点を以下の通り抜粋します。
- $geoNearは、パイプラインの最初のステージとしてのみ使用できます。
- 地理空間インデックスが 1 つしかない場合は、$geoNear は暗黙的にインデックス付きフィールドを計算に使用します。
実装サンプル
以下のような形式のドキュメントを用意します。 2dsphereのインデックスをlon_latの項目に適用しておきます。
{
"_id": "453a76e1-3c03-4983-b616-b80e1a0103d7"
"name": "高尾山",
"create_user_account_id": "sample_user_id_1",
"address": "東京都八王子市高尾町",
"lon_lat": [
139.261831,
35.633417
],
"prefecture_code": "13",
"detail": "",
"url": "https://www.jalan.net/kankou/spt_guide000000187656/"
}
これをmongoengineを使用して、aggregateのクエリを発行するサンプル実装は以下です。
def find_my_posts_by_lat_lon(
user_account_id: str,
lon: float,
lat: float,
radius_meter: float,
limit: int,
) -> list:
pipeline = [
{
"$geoNear": {
"near": {
"type": "Point",
"coordinates": [lon, lat],
},
"distanceField": "distance",
"maxDistance": radius_meter,
"spherical": True,
}
},
{"$match": {"create_user_account_id": user_account_id}},
{"$limit": limit},
{
"$project": {
"_id": 1,
"name": 1,
"address": 1,
"lon_lat": 1,
"prefecture_code": 1,
"detail": 1,
"url": 1,
}
},
]
// 事前にmongoengineでドキュメントのclassを定義しておく
return list(PostPlace.objects().aggregate(pipeline))
Discussion