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

基于MongoDB实现位置分组查询,筛选间距≥10公里的结果

解决方案:基于地理网格分组实现点聚合

针对1000万条充电站数据的地图展示性能问题,我们可以通过地理网格分组的方式,将距离小于10公里的充电站合并为一个返回结果,具体实现如下:

方案一:自定义经纬度网格分组(精准10公里间隔)

该方案通过计算每个充电站所在的10公里网格编号,按网格分组后每组返回一条数据,能精准控制点之间的最小间距:

const stations = require('./path/to/your/stationsModel');

// 地图视口过滤(可选,优先过滤减少数据量)
const mapBounds = {
  sw: [10.0, 40.0], // 西南角经纬度 [经度, 纬度]
  ne: [20.0, 50.0]  // 东北角经纬度
};

stations.aggregate([
  // 第一步:过滤当前地图视口内的数据(大幅减少后续处理量)
  {
    $match: {
      loc: {
        $geoWithin: {
          $box: [mapBounds.sw, mapBounds.ne]
        }
      }
    }
  },
  // 第二步:计算每个点所属的10公里网格编号
  {
    $addFields: {
      // 纬度每度≈111公里,10公里对应≈0.09009度,取整到该倍数的网格
      latGrid: {
        $round: [{ $divide: ["$loc.coordinates.1", 0.09009] }, 0]
      },
      // 经度距离随纬度变化,计算10公里对应的经度间隔后取整
      lngGrid: {
        $round: [
          {
            $divide: [
              "$loc.coordinates.0",
              {
                $divide: [
                  10,
                  { $multiply: [111, { $cos: { $multiply: ["$loc.coordinates.1", Math.PI / 180] } }] }
                ]
              }
            ]
          },
          0
        ]
      }
    }
  },
  // 第三步:按网格分组,每组随机取一条数据(也可用$first取第一条)
  {
    $group: {
      _id: { latGrid: "$latGrid", lngGrid: "$lngGrid" },
      station: { $sample: { size: 1 } }
    }
  },
  // 第四步:将分组后的station作为根文档返回
  {
    $replaceRoot: { newRoot: "$station" }
  }
])
.exec()
.then(aggregatedStations => {
  // 处理返回的聚合后数据
  console.log(aggregatedStations);
})
.catch(err => {
  console.error('聚合查询失败:', err);
});

方案二:GeoHash分组(快速实现近似间隔)

GeoHash是一种将地理位置编码为字符串的算法,相同前缀的GeoHash代表同一区域,可快速实现近似的区域聚合:

stations.aggregate([
  // 可选:先过滤视口数据
  {
    $match: {
      loc: {
        $geoWithin: {
          $box: [mapBounds.sw, mapBounds.ne]
        }
      }
    }
  },
  // 计算GeoHash值
  {
    $addFields: {
      geoHash: { $geoHash: "$loc" }
    }
  },
  // 取GeoHash前5位(对应约4.9公里精度,若要接近10公里可改用前4位,对应约39公里)
  {
    $group: {
      _id: { $substr: ["$geoHash", 0, 5] },
      station: { $sample: { size: 1 } }
    }
  },
  {
    $replaceRoot: { newRoot: "$station" }
  }
])
.exec()
.then(results => {
  console.log(results);
});

性能优化建议

  • 优先过滤视口数据:在聚合的第一个阶段使用$match过滤当前地图视口内的数据,避免处理全量1000万条数据。
  • 确保索引生效:你的Schema已添加2dsphere索引,$geoWithin和地理相关聚合会自动使用该索引,大幅提升查询速度。
  • 选择合适的分组方式:需要精准10公里间隔用方案一,追求快速开发用方案二。
  • 避免返回冗余字段:可在聚合中添加$project阶段,只返回地图展示需要的字段(如title、loc等),减少数据传输量。

内容的提问来源于stack exchange,提问作者Nihat Yıldız - NR42

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:30:53