使用ObjectionJS操作MySQL空间列(Point类型)的增查方法咨询
没问题,我来帮你梳理下用ObjectionJS操作MySQL Point类型空间数据的具体步骤——从模型定义到插入、查询都给你讲清楚:
使用ObjectionJS操作MySQL空间数据(Point类型)
第一步:定义Objection模型
首先你需要为locations表创建对应的Objection模型,这是所有操作的基础。如果需要对空间数据做序列化/反序列化处理,也可以在模型里配置:
const { Model } = require('objection'); class Location extends Model { // 指定对应的数据表名 static get tableName() { return 'locations'; } // 可选:处理数据库返回的空间数据,转换为更易使用的格式 $parseDatabaseJson(json) { json = super.$parseDatabaseJson(json); // 把MySQL返回的Point对象转换为包含经纬度的对象(如果驱动支持直接获取x/y的话) if (json.loc_gis) { json.loc_gis = { latitude: json.loc_gis.y, longitude: json.loc_gis.x }; } return json; } }
第二步:插入空间数据
要插入Point类型的数据,需要借助MySQL的空间函数(比如ST_GeomFromText)将WKT格式的坐标字符串转换为数据库能识别的空间类型。在Objection里可以用raw方法来执行这些函数:
示例:插入一条带坐标的记录
async function addLocation() { // 构造WKT格式的Point字符串:POINT(经度 纬度),注意顺序是经、纬 const pointWkt = 'POINT(116.403874 39.914885)'; const newLocation = await Location.query().insert({ address: '北京市朝阳区某某大厦', nick_name: '我的公司', // 使用raw调用MySQL空间函数,指定坐标系EPSG:4326(WGS84全球通用坐标系) loc_gis: Location.raw('ST_GeomFromText(?, 4326)', [pointWkt]), loc_type: 'office' }); console.log('插入成功的记录:', newLocation); }
你也可以用ST_Point函数直接构造坐标,效果是一样的:
loc_gis: Location.raw('ST_Point(?, ?, 4326)', [116.403874, 39.914885])
第三步:查询空间数据
空间查询的核心是使用MySQL的空间函数,比如计算距离、判断点是否在区域内等,同样通过Objection的raw方法来实现。
示例1:查询指定坐标附近的地点
用ST_Distance_Sphere函数计算两个点之间的球面距离(单位:米),筛选10公里以内的地点:
async function getNearbyLocations(targetLng, targetLat) { const nearby = await Location.query() // 选择需要的字段,同时计算距离并别名 .select( 'locid', 'address', 'nick_name', Location.raw( 'ST_Distance_Sphere(loc_gis, ST_GeomFromText(?, 4326)) AS distance', [`POINT(${targetLng} ${targetLat})`] ) ) // 筛选距离小于等于10000米(10公里)的记录 .where( Location.raw( 'ST_Distance_Sphere(loc_gis, ST_GeomFromText(?, 4326)) <= ?', [`POINT(${targetLng} ${targetLat})`, 10000] ) ) // 按距离从近到远排序 .orderBy('distance', 'asc'); console.log('附近的地点:', nearby); } // 调用示例:查询(116.403874, 39.914885)附近的地点 getNearbyLocations(116.403874, 39.914885);
示例2:查询指定区域内的地点
用ST_Contains函数判断点是否在某个多边形范围内,比如查询一个矩形区域内的所有地点:
async function getLocationsInPolygon() { // 定义多边形的WKT格式,注意要闭合(首尾点一致) const polygonWkt = 'POLYGON((116.38 39.90, 116.42 39.90, 116.42 39.92, 116.38 39.92, 116.38 39.90))'; const locationsInArea = await Location.query() .select('locid', 'address', 'nick_name') .where( Location.raw('ST_Contains(ST_GeomFromText(?, 4326), loc_gis)', [polygonWkt]) ); console.log('指定区域内的地点:', locationsInArea); }
示例3:将空间数据转为可读格式
如果需要把数据库返回的Point类型转为字符串格式(方便前端处理),可以用ST_AsText函数:
async function getLocationsWithWkt() { const locations = await Location.query() .select( 'locid', 'address', Location.raw('ST_AsText(loc_gis) AS loc_gis_wkt') ); // 返回的loc_gis_wkt格式为:POINT(经度 纬度) console.log('带WKT坐标的地点:', locations); }
额外优化:添加空间索引
为了提升空间查询的性能,建议给loc_gis列添加空间索引。你可以在Knex的表定义里加上这一行:
knex.schema.createTable('locations',function(table){ table.increments('locid').primary(); table.string('address').notNullable(); table.string('nick_name'); table.specificType('loc_gis','Point').nullable(); table.enu('loc_type',['home','office','college','other']).notNullable(); table.timestamps(); // 添加空间索引 table.spatialIndex('loc_gis'); })
内容的提问来源于stack exchange,提问作者Jagan Veeraraghavan
相关产品推荐
相关产品推荐

