NodeJS Sequelize查询MySQL5.7地图点位 获取无重名最近3个结果
实现方案
你需要借助Sequelize.literal写入原生的距离计算逻辑,再通过过滤保留每个名称下距离最近的点位,最终排序取前3条即可,具体实现如下:
前提说明
假设你已经提前定义好了Pin模型对应pins表,给定的目标坐标为纬度targetLat = 13、经度targetLng = 22。
代码实现
// 构造Haversine距离计算表达式,计算结果单位为米 const calculateDistance = sequelize.literal(` 6371 * 1000 * ACOS( COS(RADIANS(${targetLat})) * COS(RADIANS(latitude)) * COS(RADIANS(${targetLng}) - RADIANS(longitude)) + SIN(RADIANS(${targetLat})) * SIN(RADIANS(latitude)) ) `); // 第一种:兼容性最高的写法,不依赖MySQL非标准配置 const result = await Pin.findAll({ attributes: ['id', 'name', 'latitude', 'longitude', [calculateDistance, 'distance']], // 过滤条件:仅保留每个name下距离最近的点位 where: sequelize.where(calculateDistance, '=', sequelize.literal(` (SELECT MIN( 6371 * 1000 * ACOS( COS(RADIANS(${targetLat})) * COS(RADIANS(latitude)) * COS(RADIANS(${targetLng}) - RADIANS(longitude)) + SIN(RADIANS(${targetLat})) * SIN(RADIANS(latitude)) ) ) FROM pins p2 WHERE p2.name = pins.name) `)), // 按距离升序排序 order: [[sequelize.literal('distance'), 'ASC']], // 取前3条 limit: 3, raw: true });
简化写法(仅适合关闭了ONLY_FULL_GROUP_BY的MySQL 5.7环境)
如果你的数据库调整了SQL模式,允许非分组字段出现在查询结果中,可以用更短的写法:
const result = await Pin.findAll({ attributes: ['id', 'name', 'latitude', 'longitude', [calculateDistance, 'distance']], group: 'name', order: [[sequelize.literal('distance'), 'ASC']], limit: 3, raw: true });
该写法依赖MySQL非标准的GROUP BY特性,分组时会自动取排序后的第一条记录,也能拿到每个name最近的点位。
内容的提问来源于stack exchange,提问作者Zhang Zhan
相关产品推荐
相关产品推荐

