7

有什么方法可以使用满足以下条件的mongodb地理空间查询来查询和获取位置数据?MongoDB - 两个多边形的地理空间相交

  • 获取属于两个框或一般两个多边形之间相交部分的所有位置。

例如下面我们可以在查询输出中只得到黄色区域内实际上是紫色和红色几何对象[多边形]的公共区域的位置?

enter image description here

我的MongoDB文档的研究至今

使用情况

db.places.find({ 
    loc: { $geoWithin: { $box: [ [ 0, 0 ], [ 100, 100 ] ] } } 
}) 

上面的查询提供了一个矩形几何面积[我要寻找的是共用于两个这样的单个查询位置]

db.places.find({ 
    loc: { $geoWithin: { $box: [ [ 0, 0 ], [ 100, 100 ] ] } } 
}) 

    db.places.find({ 
    loc: { $geoWithin: { $box: [ [ 50, 50 ], [ 90, 120 ] ] } } 
}) 
+0

这有帮助吗? -http://docs.mongodb.org/manual/reference/operator/query/geoIntersects/#example。请在您的收藏中包含描述坐标的示例文档。 – BatScream

+0

@BatScream 的示例文档如下: { “_id”: “35004”, “城市”: “ACMAR”, “LOC”:[ -86.51557, 33.584132 ], “流行” :6055, “状态”:“AL” } – Viraj

+0

@BatScream感谢您的回应。实际上,您提供的mongodb文档链接提供了基于多边形的结果。我在寻找这样的东西。 1.首先查询得到方框A内的结果。 2.其次查询得到方框B内的结果。 3.第三查询输出对于方框A和B都通用的结果,这意味着查询提供了与两个方向的交集盒子或者通常可以是两个多边形:D。有没有办法做到这一点? – Viraj

回答

5

左右的时间内结果用清新的头脑看着这个问题,答案就是把我凝视在脸上。你已经说过的关键是你想在一个响应中找到两个查询的“交集”。

查看此问题的另一种方法是,您希望由第一个查询绑定的所有点随后将作为第二个查询的“输入”,并根据需要依此类推。这基本上是一个交集,但逻辑实际上是字面的。

所以只需使用aggregation framework链接匹配的查询。举个简单的例子,考虑以下文件:

{ "loc" : { "type" : "Point", "coordinates" : [ 4, 4 ] } } 
{ "loc" : { "type" : "Point", "coordinates" : [ 8, 8 ] } } 
{ "loc" : { "type" : "Point", "coordinates" : [ 12, 12 ] } } 

而且链式聚合管道,只有两个疑问:

db.geotest.aggregate([ 
    { "$match": { 
     "loc": { 
      "$geoWithin": { 
       "$box": [ [0,0], [10,10] ] 
      } 
     } 
    }}, 
    { "$match": { 
     "loc": { 
      "$geoWithin": { 
       "$box": [ [5,5], [20,20] ] 
      } 
     } 
    }} 
]) 

所以,如果你认为在逻辑上,第一个结果会发现,落在点在最初的方框或前两个项目的范围内。然后,这些结果将由第二个查询执行,并且由于新框区起始于排除第一个点的[5,5]。第三点已经被排除在外,但是如果方块限制被逆转,那么结果将只是相同的中间文件。

是如何工作的相当独特的$geoWithin查询运营商相比,其他各种地理功能:

$geoWithin不需要地理空间索引。但是,地理空间索引将提高查询性能。 2dsphere2d地理空间索引都支持$geoWithin

所以结果是好的和坏的。好的是,您可以在没有索引的情况下执行此类操作,但不好,因为一旦聚合管道在第一个查询操作后更改了收集结果,就无法使用更多索引。因此,在合并来自支持的初始Polygon/MultiPolygon之后的任何“设置”结果时,索引的任何性能优势都会丢失。


出于这个原因,我还是建议你计算交点界发出的MongoDB查询的“外部”。尽管聚合框架可以做到这一点,但由于流水线的“链接”性质,即使所得到的交叉点会越来越小,您的最佳性能是具有可以使用所有索引优点的正确边界的单个查询。

有很多种方法可以做到这一点,但这里的参考是使用JSTS库的实现,该库是流行的用于Java的JTS库的JavaScript端口。有可能是其他公司或其他语言的港口,但这简单的GeoJSON的解析和内置了对这种事情的方法是让交叉口范围:

var async = require('async'); 
    util = require('util'), 
    jsts = require('jsts'), 
    mongo = require('mongodb'), 
    MongoClient = mongo.MongoClient; 

var parser = new jsts.io.GeoJSONParser(); 

var polys= [ 
    { 
    type: 'Polygon', 
    coordinates: [[ 
     [ 0, 0 ], [ 0, 10 ], [ 10, 10 ], [ 10, 0 ], [ 0, 0 ] 
    ]] 
    }, 
    { 
    type: 'Polygon', 
    coordinates: [[ 
     [ 5, 5 ], [ 5, 20 ], [ 20, 20 ], [ 20, 5 ], [ 5, 5 ] 
    ]] 
    } 
]; 

var points = [ 
    { type: 'Point', coordinates: [ 4, 4 ] }, 
    { type: 'Point', coordinates: [ 8, 8 ] }, 
    { type: 'Point', coordinates: [ 12, 12 ] } 
]; 

MongoClient.connect('mongodb://localhost/test',function(err,db) { 

    db.collection('geotest',function(err,geo) { 

    if (err) throw err; 

    async.series(
     [ 
     // Insert some data 
     function(callback) { 
      var bulk = geo.initializeOrderedBulkOp(); 
      bulk.find({}).remove(); 
      async.each(points,function(point,callback) { 
      bulk.insert({ "loc": point }); 
      callback(); 
      },function(err) { 
      bulk.execute(callback); 
      }); 
     }, 

     // Run each version of the query 
     function(callback) { 
      async.parallel(
      [ 
       // Aggregation 
       function(callback) { 
       var pipeline = []; 
       polys.forEach(function(poly) { 
        pipeline.push({ 
        "$match": { 
         "loc": { 
         "$geoWithin": { 
          "$geometry": poly 
         } 
         } 
        } 
        }); 
       }); 

       geo.aggregate(pipeline,callback); 
       }, 

       // Using external set resolution 
       function(callback) { 
       var geos = polys.map(function(poly) { 
        return parser.read(poly); 
       }); 

       var bounds = geos[0]; 

       for (var x=1; x<geos.length; x++) { 
        bounds = bounds.intersection(geos[x]); 
       } 

       var coords = parser.write(bounds); 

       geo.find({ 
        "loc": { 
        "$geoWithin": { 
         "$geometry": coords 
        } 
        } 
       }).toArray(callback); 
       } 
      ], 
      callback 
     ); 
     } 
     ], 
     function(err,results) { 
     if (err) throw err; 
     console.log(
      util.inspect(results.slice(-1), false, 12, true)); 
     db.close(); 
     } 
    ); 

    }); 

}); 

使用完整GeoJSON的“多边形”表示没有为这相当于什么JTS可以理解和使用。您可能会收到的任何真实应用程序的输入都是以这种格式显示,而不是应用便利性,例如$box

因此可以使用聚合框架,甚至并行查询来合并结果的“集合”。但是,虽然聚合框架可能比从外部合并结果集更好,但最好的结果总是来自先计算边界。

+1

大!需要一些时间来解决你的解决方案,虽然......看起来很有前景:D – Viraj

+0

在这种情况下使用两阶段聚合看起来最好 – Viraj

0

如果其他人看起来这样,从mongo 2.4版开始,可以使用$geoIntersects来查找GeoJSON对象的交集,这些对象支持两个多边形的交集以及其他类型的交集。

{ 
    <location field>: { 
    $geoIntersects: { 
     $geometry: { 
      type: "<GeoJSON object type>" , 
      coordinates: [ <coordinates> ] 
     } 
    } 
    } 
} 

有一个很好的写作on this blog

+0

实际上没有。该问题要求发送“两个或更多个多边形”,并查看“那些”形状是否“插入”并包含在“该结果的交集”内找到的“点”。 '$ geoInsersects'用于搜索“使用”几何对象,并查找“集合”中的任何“几何对象”实际上是否与查询中发出的对象“交叉边界”。这是两个“完全”不同的东西。 –

相关问题