在開發基於位置的服務(LBS)應用時,高效儲存與查詢地理坐標至關重要。MongoDB 內建強大的地理空間索引,支援平面(2d)與球面(2dsphere)兩種模式,適合處理經緯度資料。
首先切換至 lbs 資料庫,並插入幾個範例地點,採用 GeoJSON 格式的 Point 類型:
use lbs;
db.lbs.insert({ loc: { type: "Point", coordinates: [113.332264, 23.156206] }, name: "廣州東站" });
db.lbs.insert({ loc: { type: "Point", coordinates: [113.330611, 23.147234] }, name: "林和西" });
db.lbs.insert({ loc: { type: "Point", coordinates: [113.328095, 23.165376] }, name: "天平架" });
為 loc 欄位建立球面索引,以支援球面幾何查詢:
db.lbs.ensureIndex({ loc: "2dsphere" });
假設使用者位於「時代廣場」(經度 113.323568,緯度 23.146436),搜尋半徑 1 公里內的地點,並按距離由近及遠排序:
db.lbs.find({
loc: {
$near: {
$geometry: { type: "Point", coordinates: [113.323568, 23.146436] },
$maxDistance: 1000
}
}
});
查詢結果將回傳符合條件的文件,例如「林和西」。
以下 PHP 程式示範如何連線 MongoDB、插入隨機坐標、並執行鄰近搜尋。請先在 MongoDB 中建立使用者並啟用認證:
use lbs;
db.createUser({ user: "root", pwd: "123456", roles: [] });
db.auth({ user: "root", pwd: "123456" });
核心 PHP 程式碼:
selectDB($dbname);
} catch (MongoException $e) {
throw new ErrorException('無法連線資料庫: ' . $e->getMessage(), 31);
}
}
// 插入坐標
function add($dbconn, $tablename, $longitude, $latitude, $name) {
$coll = $dbconn->selectCollection($tablename);
$coll->ensureIndex(['loc' => '2dsphere']);
$data = [
'loc' => ['type' => 'Point', 'coordinates' => [floatval($longitude), floatval($latitude)]],
'name' => $name
];
$result = $coll->insert($data, ['w' => true]);
return isset($result['ok']) && $result['ok'];
}
// 搜尋附近坐標(公里為單位)
function query($dbconn, $tablename, $longitude, $latitude, $maxdistance, $limit = 10) {
$coll = $dbconn->selectCollection($tablename);
$param = [
'loc' => [
'$nearSphere' => [
'$geometry' => ['type' => 'Point', 'coordinates' => [floatval($longitude), floatval($latitude)]],
'$maxDistance' => $maxdistance * 1000
]
]
];
$cursor = $coll->find($param)->limit($limit);
return iterator_to_array($cursor);
}
// 示例執行
$db = conn('localhost', 'lbs', 'root', '123456');
// 批次插入 100 筆隨機測試資料
for ($i = 0; $i < 100; $i++) {
$longitude = '113.3' . mt_rand(10000, 99999);
$latitude = '23.15' . mt_rand(1000, 9999);
$name = 'name' . mt_rand(10000, 99999);
add($db, 'lbs', $longitude, $latitude, $name);
}
// 搜尋 1 公里內地點
$longitude = 113.323568;
$latitude = 23.146436;
$result = query($db, 'lbs', $longitude, $latitude, 1);
print_r($result);
?>
利用球面三角公式(Haversine 公式),根據地球半徑計算兩點間的最短距離。支援公尺與公里兩種單位,並可指定小數位數。
這兩個功能結合起來,即可構建完整的 LBS 核心服務:MongoDB 負責高效的空間索引與篩選,PHP 函數提供精確的距離計算,滿足「附近的人」、「門店查詢」、「物流追蹤」等多種場景需求。