github.com/g0v/twgeojson
而 Metabase 目前只支援 geojson 格式,所以我們就下載這 2 個檔,以 twTown1982.geo.json 為例
到 github.com/g0v/twgeojson/json,有數個 json 檔,其中 twTown1982.geo.json 是區級行政區,twVillage1982.geo.json 則是 里(村)級。
另有 twTown1982.topo.json 及 twVillage1982.topo.json,是 geo.json 的後繼優化格式,簡略記一下主要的差異:就是相鄰的 2 個區中間的界線不重複記錄。
例如:A 區與 B 區相鄰,geo.json 是完整地記錄 A 區的座標點 [1,2,3,4,5] 及 B 區的座標點 [1,6,7,8,9,2],如此 點 1 及 點 2 就被記錄了 2 次,而 topo.json 則透過拓撲方法只記錄 1 次 點1到點2 的弧線,相較之下,topo.json 的檔案就比較小。
點擊 twTown1982.geo.json
→ 點擊【下載】圖示下載 json 檔
→ 將 twTown1982.geo.json 放置在 /var/www/html/ 下,然後在 Metabase 設定 twTown1982.geo.json 的 url,在本例為 http://localhost/twTown1982.geo.json
瞄一下檔案內容
{"type": "FeatureCollection",
"features": [
...
...
{"properties":{"TOWNSN":"64000002","TOWNID":"6400003","COUNTYNAME":"高雄市","TOWNNAME":"左營區","name":"高雄市/左營區"},
"type":"Feature",
"geometry":{"type": "Polygon",
"coordinates": [[[ 120.274766995608132, 22.706593189102705 ],
...
...
]]
}
},
...
...
登入 Metabase,點擊【齒輪】圖示
→ 管理員設定
→ 地圖 → 新增一個地圖
→【URL】輸入 http://localhost/twTown1982.geo.json
→【區域識別符】選擇 TOWNID
→【區域顯示名稱】選擇 TOWNNAME
g0v/twgeojson 的是 2014 年的資料,理論上這幾年並沒有重新劃分區級行政區,所以資料應該仍可信、準確。
g0v/twgeojson/json/twVillage1982.geo.json 則更細, 行政區範圍小至 "村/里",村/里的劃分就可能不定期會變動了,例如老人家居住的里聽說最慢 2027 年就將要拆成 4 個里。
建立區級資料表存放 geojson 的資料,在本筆記,資料表命名為 town_geo
CREATE TABLE `town_geo` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`TOWNSN` VARCHAR(20),
`TOWNID` VARCHAR(20),
`COUNTYNAME` VARCHAR(50),
`TOWNNAME` VARCHAR(50),
`name` VARCHAR(100),
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
寫一個 php 讀取 twTown1982.geo.json 並存入 town_geo
<?php
ini_set('display_errors', 1);
ini_set('memory_limit', '512M'); // 放寬記憶體限制, 才能讀大檔案
// 資料庫連線設定
$host = 'localhost';
$dbname = '資料庫名稱';
$username = '帳號';
$password = '密碼';
try {
// 1. 建立 PDO 連線
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 2. 讀取並解析 GeoJSON 檔案
$jsonFile = 'twTown1982.geo.json';
if (!file_exists($jsonFile)) {
die("錯誤:找不到檔案 $jsonFile");
}
$jsonContent = file_get_contents($jsonFile);
$data = json_decode($jsonContent, true);
if ($data === null) {
die("錯誤:JSON 解析失敗");
}
// 3. 準備 SQL 插入語句
$sql = "INSERT INTO town_geo (TOWNSN, TOWNID, COUNTYNAME, TOWNNAME, name)
VALUES (:townsn, :townid, :countyname, :townname, :name)";
$stmt = $pdo->prepare($sql);
// 4. 開始交易 (Transaction) 以提升大量寫入的速度
$pdo->beginTransaction();
$count = 0;
foreach ($data['features'] as $feature) {
$props = $feature['properties'];
// 綁定參數並執行
$stmt->execute([
':townsn' => $props['TOWNSN'] ?? null,
':townid' => $props['TOWNID'] ?? null,
':countyname' => $props['COUNTYNAME'] ?? null,
':townname' => $props['TOWNNAME'] ?? null,
':name' => $props['name'] ?? null
]);
$count++;
}
// 5. 提交交易
$pdo->commit();
echo "成功!共匯入 $count 筆資料。";
} catch (PDOException $e) {
// 發生錯誤時回滾
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollBack();
}
echo "資料庫錯誤:" . $e->getMessage();
} catch (Exception $e) {
echo "一般錯誤:" . $e->getMessage();
}
?>
如此就能結合自己的資料表,建立區級行政區的圖表了。
再建立里(村)級資料表,在本例為 village_geo
CREATE TABLE `village_geo` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`VILLAGESN` VARCHAR(20),
`VILLAGEID` VARCHAR(20),
`COUNTYNAME` VARCHAR(50),
`TOWNNAME` VARCHAR(50),
`VILLAGENAM` VARCHAR(50),
`name` VARCHAR(150),
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
寫一個 php 讀取 twVillage1982.geo.json 並存入 village_geo
<?php
// 1. 提高記憶體限制(針對較大的村里 GeoJSON 檔案)
ini_set('memory_limit', '512M');
set_time_limit(0); // 取消執行時間限制
// 資料庫連線設定
$host = 'localhost';
$dbname = '資料庫名稱';
$username = '帳號';
$password = '密碼';
try {
// 2. 建立 PDO 連線
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 3. 讀取 GeoJSON 檔案
$jsonFile = 'twVillage1982.geo.json';
if (!file_exists($jsonFile)) {
die("錯誤:找不到檔案 $jsonFile");
}
echo "正在讀取檔案...\n";
$jsonContent = file_get_contents($jsonFile);
echo "正在解析 JSON...\n";
$data = json_decode($jsonContent, true);
// 解析完立刻釋放字串記憶體
unset($jsonContent);
if ($data === null) {
die("錯誤:JSON 解析失敗,請檢查檔案格式。");
}
// 4. 準備 SQL 插入語句
$sql = "INSERT INTO village_geo (VILLAGESN, VILLAGEID, COUNTYNAME, TOWNNAME, VILLAGENAM, name)
VALUES (:v_sn, :v_id, :c_name, :t_name, :v_name, :full_name)";
$stmt = $pdo->prepare($sql);
// 5. 開始交易處理 (大量資料寫入必備)
$pdo->beginTransaction();
echo "正在匯入資料...\n";
$count = 0;
foreach ($data['features'] as $feature) {
$props = $feature['properties'];
$stmt->execute([
':v_sn' => $props['VILLAGESN'] ?? null,
':v_id' => $props['VILLAGEID'] ?? null,
':c_name' => $props['COUNTYNAME'] ?? null,
':t_name' => $props['TOWNNAME'] ?? null,
':v_name' => $props['VILLAGENAM'] ?? null,
':full_name' => $props['name'] ?? null
]);
$count++;
}
// 6. 提交交易
$pdo->commit();
echo "匯入完成!成功存入 $count 筆村里資料。";
} catch (PDOException $e) {
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollBack();
}
echo "資料庫錯誤:" . $e->getMessage();
} catch (Exception $e) {
echo "一般錯誤:" . $e->getMessage();
}
?>
匯入的記錄如下圖
如果您需要的圖資精細顆粒度要小到村/里,國土測繪中心在政府資料開放平臺(opendata) 也有提供圖資,感覺有提續在更新,可能會較適合您,但國土測繪中心沒有直接提供 geo.json 格式,我們需要轉換程式幫忙。
到 村里界圖(TWD97經緯度),點擊【資料資源下載網址】,下載的是壓縮檔,找個目錄解壓縮存放,會看到解壓出來的檔案中有副檔名 .shp 的檔案,這是主檔。
功能表 【Layer】→【Save As】→【Format】欄位選擇 GeoJSON → 輸入檔名,在本例為 town_twd97 → 按下【確定】鈕
開啟檔案,會發現 properties 內的欄位跟上面 g0v 的不同,由此可知,properties 的欄位是各自定義的;所以,若您圖資是選擇國土測繪中心的,需注意匯入資料的欄位也會不同。
相關筆記 ----

















































