如何使用Sequelize ORM按经纬度距离查询排序商铺列表
Sequelize 实现周边商铺查询方案
实现核心是通过球面距离公式计算用户与商铺的位置距离,再完成范围筛选、排序,以下是修改后的可运行代码:
const { Op, literal } = require('sequelize'); // 先把传入的经纬度转为数值类型,避免字符串导致计算错误 const userLat = parseFloat(req.query.latitude); const userLon = parseFloat(req.query.longitude); const radius = 5; // 自定义查询范围,单位:公里,可根据需求调整 const limit = req.query.limit || 10; const offset = req.query.offset || 0; const category_id = req.query.category_id; const shopLists = await Shop.findAll({ limit, offset, attributes: [ // 按需补充需要返回的商铺字段 'id', 'name', 'address', 'latitude', 'longitude', // 新增计算距离的字段,单位为公里 [ literal(` 6371 * acos( cos(radians(${userLat})) * cos(radians(latitude)) * cos(radians(longitude) - radians(${userLon})) + sin(radians(${userLat})) * sin(radians(latitude)) ) `), 'distance' ] ], where: { category_id: category_id, status: 1, // 筛选距离在指定范围内的商铺 [Op.and]: literal(` 6371 * acos( cos(radians(${userLat})) * cos(radians(latitude)) * cos(radians(longitude) - radians(${userLon})) + sin(radians(${userLat})) * sin(radians(latitude)) ) <= ${radius} `) }, include: { model: Category, attributes: ['id', 'name'] }, // 按距离从近到远排序 order: [[literal('distance'), 'ASC']] });
优化说明
如果你使用的是MySQL 5.7及以上版本,可以用内置的ST_Distance_Sphere函数简化计算,写法更简洁、性能更好,直接将上面代码中计算距离的Haversine公式替换为以下内容即可,返回单位同样为公里:
literal(`ST_Distance_Sphere(point(longitude, latitude), point(${userLon}, ${userLat})) / 1000`)
注意事项
- 如果数据量较大,建议给
latitude、longitude、category_id、status字段加联合索引,或者直接使用数据库的空间索引优化查询速度 - 如果需要自定义返回距离的小数位数,可以在计算距离的SQL外层加
ROUND()函数调整精度
内容的提问来源于stack exchange,提问作者Mithen
相关产品推荐
相关产品推荐

