Strapi API:如何设置自定义查询服务查找指定范围内的最近机场?
当然可以实现这个需求!我们可以结合geodist工具和Strapi的查询逻辑,轻松筛选出指定距离范围内的机场。下面分两种方案详细说明,你可以根据数据量和性能需求选择:
方案一:使用geodist在内存中筛选(适合小数据量场景)
这种方式先查询所有符合基础条件的机场,再用geodist计算距离并筛选,实现简单,适合机场数据量不大的情况。
1. 确保依赖安装
如果你还没安装geodist,先执行命令:
npm install geodist # 或者用yarn yarn add geodist
2. 调整路由配置
原路由的findOne是返回单条数据,我们需要返回多条符合条件的机场,所以修改路由为自定义的findNearby方法:
{ "method": "GET", "path": "/airport/nearby/:latitude/:longitude/:distance?", "handler": "Airport.findNearby", "config": { "policies": [] } }
这里的:distance?是可选参数,默认我们可以设为100km。
3. 修改控制器逻辑
替换原有的findOne方法,新增findNearby方法:
const geodist = require('geodist'); module.exports = { async findNearby(ctx) { // 获取请求参数:当前经纬度、可选的距离阈值(默认100km) const { latitude, longitude, distance = 100 } = ctx.params; const currentLocation = { lat: parseFloat(latitude), lon: parseFloat(longitude) }; // 保留你原有的基础筛选和关联字段填充逻辑 const allAirports = await Airport.find( _.pick(ctx.params, _.keys(Airport.schema.paths)) ).populate( _.keys(_.groupBy(_.reject(strapi.models.airport.associations, { autoPopulate: false }), 'alias')).join(' ') ); // 计算每个机场与当前位置的距离,筛选出符合阈值的结果 const nearbyAirports = allAirports.filter(airport => { // 注意:这里假设你的机场模型存储经纬度的字段是`latitude`和`longitude`,如果字段名不同请自行修改 const airportLocation = { lat: airport.latitude, lon: airport.longitude }; // 以km为单位计算距离 const calculatedDistance = geodist(currentLocation, airportLocation, { unit: 'km' }); return calculatedDistance <= parseFloat(distance); }); return nearbyAirports; } };
方案二:使用数据库地理索引查询(适合大数据量,性能更优)
如果你的机场数据量很大,内存筛选会导致性能瓶颈,这时推荐用数据库的地理查询能力(比如MongoDB的2dsphere索引、PostgreSQL的PostGIS扩展),直接在数据库层面完成筛选,效率更高。
以MongoDB为例:
1. 更新机场模型定义
在models/Airport.settings.json中添加地理字段和索引:
{ "attributes": { // 替换原有的latitude/longitude字段,新增地理点字段 "location": { "type": "geometry", "default": "Point", "required": true }, // 其他原有字段... }, "indexes": [ { "keys": { "location": "2dsphere" } } ] }
注意:MongoDB存储地理点的格式是[经度, 纬度],和常规的经纬度顺序相反。
2. 修改控制器查询逻辑
async findNearby(ctx) { const { latitude, longitude, distance = 100 } = ctx.params; // 将km转换为米(MongoDB的$maxDistance默认单位是米) const maxDistanceInMeters = parseFloat(distance) * 1000; // 直接用MongoDB的地理查询语法筛选附近机场 const nearbyAirports = await Airport.find({ location: { $nearSphere: { $geometry: { type: "Point", coordinates: [parseFloat(longitude), parseFloat(latitude)] // 注意顺序是[lon, lat] }, $maxDistance: maxDistanceInMeters } }, // 保留原有的基础筛选条件 ..._.pick(ctx.params, _.keys(Airport.schema.paths)) }).populate( _.keys(_.groupBy(_.reject(strapi.models.airport.associations, { autoPopulate: false }), 'alias')).join(' ') ); return nearbyAirports; }
注意事项
- 如果你用方案一,要确保机场模型的经纬度字段是数值类型(Number),否则计算距离会出错。
- 方案二需要数据库支持地理查询,不同数据库的语法略有差异,比如PostgreSQL需要安装PostGIS扩展后使用对应的查询语句。
内容的提问来源于stack exchange,提问作者Bishnu Kumar Bhakat
相关产品推荐
相关产品推荐

