Drizzle | PostGIS 几何点
This guide assumes familiarity with:
- 了解如何使用 PostgreSQL
- Postgis 扩展
- 索引
- 选择语句中的过滤
- SQL 操作符
PostGIS 通过支持存储、索引和查询地理空间数据来扩展 PostgreSQL 关系数据库的能力。
目前,Drizzle 不会自动创建扩展,因此您需要手动创建。创建一个空的迁移文件并添加 SQL 查询:
npx drizzle-kit generate --customCREATE EXTENSION postgis;以下是您在 Drizzle 中如何创建具有 geometry 数据类型和空间索引的表:
schema.ts
migration.sql
import { geometry, index, pgTable, serial, text } from 'drizzle-orm/pg-core';
export const stores = pgTable(
'stores',
{
id: serial('id').primaryKey(),
name: text('name').notNull(),
location: geometry('location', { type: 'point', mode: 'xy', srid: 4326 }).notNull(),
},
(t) => [
index('spatial_index').using('gist', t.location),
]
);以下是您如何在 Drizzle 中插入 geometry 数据。PostGIS 中的 ST_MakePoint() 使用指定的坐标创建一个 point 类型的几何对象。
ST_SetSRID() 将几何图形上的 SRID(与特定坐标系统、容差和分辨率关联的唯一标识符)设置为特定的整数值:
// mode: 'xy'
await db.insert(stores).values({
name: 'Test',
location: { x: -90.9, y: 18.7 },
});
// mode: 'tuple'
await db.insert(stores).values({
name: 'Test',
location: [-90.9, 18.7],
});
// sql raw
await db.insert(stores).values({
name: 'Test',
location: sql`ST_SetSRID(ST_MakePoint(-90.9, 18.7), 4326)`,
});要计算对象之间的距离,您可以使用 <-> 操作符和 ST_Distance() 函数,对于 geometry types 返回两个几何形状之间的最小平面距离。这是您如何在 Drizzle 中通过 PostGIS 查询最近的位置:
import { getTableColumns, sql } from 'drizzle-orm';
import { stores } from './schema';
const point = {
x: -73.935_242,
y: 40.730_61,
};
const sqlPoint = sql`ST_SetSRID(ST_MakePoint(${point.x}, ${point.y}), 4326)`;
await db
.select({
...getTableColumns(stores),
distance: sql`ST_Distance(${stores.location}, ${sqlPoint})`,
})
.from(stores)
.orderBy(sql`${stores.location} <-> ${sqlPoint}`)
.limit(1);select *, ST_Distance(location, ST_SetSRID(ST_MakePoint(-73.935_242, 40.730_61), 4326))
from stores order by location <-> ST_SetSRID(ST_MakePoint(-73.935_242, 40.730_61), 4326)
limit 1;要过滤位于指定矩形区域内的商店,您可以使用 ST_MakeEnvelope() 和 ST_Within() 函数。ST_MakeEnvelope() 从 X 和 Y 的最小值和最大值创建一个矩形多边形。ST_Within() 如果几何图形 A 在几何图形 B 内部则返回 TRUE。
const point = {
x1: -88,
x2: -73,
y1: 40,
y2: 43,
};
await db
.select()
.from(stores)
.where(
sql`ST_Within(
${stores.location}, ST_MakeEnvelope(${point.x1}, ${point.y1}, ${point.x2}, ${point.y2}, 4326)
)`,
);select * from stores where ST_Within(location, ST_MakeEnvelope(-88, 40, -73, 43, 4326));