You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 19:09:02