搜索位于距离mongoDB中的路径给定距离内的点

时间:2017-11-07 16:09:46

标签: mongodb

以下是商业文档,其中address.location是我保存坐标的地方。

{
    "_id" : ObjectId("59944c26085e1140d4575393"),
    "category" : "place",
    "address" : {
        "streetAddress" : "19210 Clay Road",
        "city" : "Katy",
        "zipcode" : "77449",
        "state" : "Texas",
        "country" : "United States",
        "countryCode" : "US",
        "locality" : "Katy, TX",
        "location" : {
            "type" : "Point",
            "coordinates" : [ 
                -95.7043599, 
                29.832139
            ]
        },
        "fomattedAddress" : "19210 Clay Rd, Katy, TX 77449"
    }
}

使用以下逻辑我计算了多边形

Coordinate[] coordinates = new Coordinate[] {new Coordinate(-84.529793, 33.961886), new Coordinate( -84.521698, 33.952987),
                new Coordinate(-84.517242, 33.944534), new Coordinate(-84.513290, 33.937264), new Coordinate( -84.498865, 33.915202), new Coordinate(-84.529793, 33.961886)};
GeometryFactory geometryFactory = new GeometryFactory();
LinearRing linear = new GeometryFactory().createLinearRing(coordinates);
Polygon polygon = new Polygon(linear, null, geometryFactory);
Coordinate[] polyCoordinates = polygon.getCoordinates();

使用下面的mongo查询我试图让多边形内的业务,但我没有结果,我做错了,请指导我

db.business.find(
   {
     "address.location.coordinates": {
       $geoIntersects: {
          $geometry: {
             type: "Polygon" ,
             coordinates: [
               [ [ -84.529793, 33.961886 ], [ -84.521698, 33.952987 ], [ -84.517242, 33.944534 ], [-84.51329, 33.937264]  , [ -84.498865, 33.915202 ], [-84.529793, 33.961886] ]
             ]
          }
       }
     }
   }
)

1 个答案:

答案 0 :(得分:0)

要查找沿路线的特定距离内的所有点,您需要在路线上建立多边

在下图中,我假设整个路线(绿色)是一条简洁明了的直线。您的查询是3个形状的$or - 半径为R的蓝色起点和终点圆,以及连接两者的红色多边形:

enter image description here

以下javascript代码https://jsfiddle.net/961kcxr3/使用基本平面几何图形计算线段的坐标。这是您需要使用您选择的语言在应用程序级别上执行的操作:

const routeCoords [ [ -84.529793, 33.961886 ], [ -84.521698, 33.952987 ], [ -84.517242, 33.944534 ], [-84.51329, 33.937264]  , [ -84.498865, 33.915202 ] ] ];

const R = 1000; // 1 km - radius to search within, adjust to your needs
const M = 1/98000; // radius to radians multiplier

const A = routeCoords[0];
const B = routeCoords[4];
const a = Math.atan2(B[0] - A[0], B[1] - A[1]) + Math.PI / 2;

var polyCoords = [ 
    [
        A[0] - Math.sin(a) * R * M,
        A[1] - Math.cos(a) * R * M
    ], [
        B[0] - Math.sin(a) * R * M,
        B[1] - Math.cos(a) * R * M
    ], [
        B[0] + Math.sin(a) * R * M,
        B[1] + Math.cos(a) * R * M
    ], [
        A[0] + Math.sin(a) * R * M,
        A[1] + Math.cos(a) * R * M
    ]
];

其中给出了poly的坐标:

[
    [-84.516182, 33.970903],
    [-84.485254, 33.924219],
    [-84.512476, 33.906185],
    [-84.543404, 33.952869]
]

结果查询:

db.business.find(
   { $or: [
       { "address.location.coordinates": {
           $geoWithin: {
              $geometry: {
                 type: "Polygon" ,
                 coordinates: [ [
                     [-84.516182, 33.970903],
                     [-84.485254, 33.924219],
                     [-84.512476, 33.906185],
                     [-84.543404, 33.952869],
                     [-84.516182, 33.970903]  // the first point to close the poly
                 ] ]
              }
           },
       } },
       { "address.location.coordinates": {
           $geoWithin: {
               $centerSphere: [ [ -84.529793, 33.961886 ], 1 / 6378.1 ] 
           }, // 1 km radius, adjust to your needs
       } },
       { "address.location.coordinates": {
           $geoWithin: {
               $centerSphere: [ [ -84.498865, 33.915202 ], 1 / 6378.1 ] 
           }, // 1 km radius, adjust to your needs
       } }
   ] }

)

现实代码应计算每个分段的多边形和圆形。它可以导致相当大的查询,因此在准确性和速度之间进行合理的平衡。

优化的一些案例:

  • 如果某段的长度明显小于半径R,则可以跳过多边形,并为该段使用2或1圈。
  • 如果角度a对于2个连续的段是相同的,则可以加入两端并将它们视为单个段,就像我在上面的示例中加入4个段一样