@northprint
// Svelteアダプターを使用
import { createDuckDB } from '@northprint/duckdb-wasm-adapter-svelte';
// データベースを初期化
const db = createDuckDB({ autoConnect: true });
// 空間分析を開始
await db.exec("INSTALL spatial");
await db.exec("LOAD spatial");
const result = db.query("SELECT ST_Distance(...)");
サーバー不要で空間分析ができる
ちなみにTurf.jsというものもあるが、今は考えない
import * as duckdb from '@duckdb/duckdb-wasm';
// WASMファイルのパスを設定
const MANUAL_BUNDLES = {
mvp: {
mainModule: './duckdb-mvp.wasm',
mainWorker: './duckdb-browser-mvp.worker.js',
},
eh: {
mainModule: './duckdb-eh.wasm',
mainWorker: './duckdb-browser-eh.worker.js',
},
};
// Worker作成とDB初期化
const bundle = await duckdb.selectBundle(MANUAL_BUNDLES);
const worker = new Worker(bundle.mainWorker);
const logger = new duckdb.ConsoleLogger();
const db = new duckdb.AsyncDuckDB(logger, worker);
await db.instantiate(bundle.mainModule, bundle.pthreadWorker);
const conn = await db.connect();
// Spatial Extensionを読み込み
await conn.query("INSTALL spatial");
await conn.query("LOAD spatial");
selectBundleがブラウザの機能を検出して自動選択
DuckDBの空間関数一覧
「好きなブランドの自動販売機はどこにある?」
SELECT id, lat, lon, operator, vending,
ST_Distance_Sphere(geom, ST_Point(139.7, 35.7)) as distance
FROM vending_machines
WHERE operator LIKE '%コカ%'
ORDER BY distance
LIMIT 10;
SELECT operator,
COUNT(*) as count,
AVG(ST_Distance_Sphere(geom, ST_Point(139.7, 35.7))) as avg_distance
FROM vending_machines
WHERE ST_DWithin(geom, ST_Point(139.7, 35.7), 10000)
AND operator IN ('コカ・コーラ', 'サントリー', 'ダイドー')
GROUP BY operator;
-- 5km圏内のブランド分布を集計
SELECT
operator,
COUNT(*) as count
FROM vending_machines
WHERE ST_DWithin(
ST_Point(lon, lat),
ST_Point(139.7, 35.7),
5000 -- 5km圏内
)
GROUP BY operator
HAVING COUNT(*) > 10
ORDER BY count DESC;
→ エリア内の主要ブランドを把握できる
-- コカ・コーラから最も近いサントリーを探す
SELECT
a.id as coca_id,
ST_Distance_Sphere(
ST_Point(a.lon, a.lat),
ST_Point(b.lon, b.lat)
) as distance_m
FROM vending_machines a, vending_machines b
WHERE a.operator = 'コカ・コーラ'
AND b.operator = 'サントリー'
AND a.id != b.id
ORDER BY distance_m
LIMIT 10;
→ 競合の配置状況を定量的に分析