【问题标题】:MongoDB - Geospatial intersection of two polygonMongoDB - 两个多边形的地理空间交集
【发布时间】:2015-02-25 08:20:56
【问题描述】:

我们有什么方法可以使用符合以下条件的 mongodb 地理空间查询来查询和获取位置数据?

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

例如,我们能否在查询输出中仅获取黄色区域内的位置,而黄色区域实际上是紫色和红色几何对象 [多边形] 的公共区域?

到目前为止我对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 ] ] } }
} )

【问题讨论】:

  • 这有帮助吗? -docs.mongodb.org/manual/reference/operator/query/geoIntersects/…。请在您的收藏中包含描述坐标的示例文档。
  • @BatScream 示例文档如下: { "_id" : "35004", "city" : "ACMAR", "loc" : [ -86.51557, 33.584132 ], "pop" : 6055 , "状态" : "AL" }
  • @BatScream 感谢您的回复。实际上,您提供的 mongodb 文档链接提供了基于多边形的结果。我正在寻找这样的东西。 1.首先查询在框 A 内获得结果。2.其次查询在框 B 内获得结果。3.第三次查询输出框 A 和 B 共有的结果,这意味着查询提供了两个框的交集,或者可能通常两个多边形:D。有办法吗?
  • 如果我做对了,那么您所要求的是从“多个”多边形定义的交集得到的“多边形”。是的?如果是这样,那么 MongoDB 将不会使用它拥有的 Geo 函数自行执行此操作。您需要首先从“交叉点”“计算”出多边形是什么,然后将其传递给$geoWithin 以查找符合该“多边形结果”的数据。这就是你想要的吗?
  • @NeilLunn 是的:) 只是想确定是否有任何直接的地理空间查询可以以这种方式工作......到目前为止我还没有找到任何这样的直接查询:(

标签: javascript mongodb mongodb-query aggregation-framework geospatial


【解决方案1】:

因此,以全新的心态看待这个问题,答案就在我眼前。您已经说过的关键是您希望在单个响应中找到两个查询的“交集”。

查看此问题的另一种方法是,您希望所有由第一个查询绑定的点都成为第二个查询的“输入”,依此类推。这本质上是交集的作用,但逻辑​​实际上是字面的。

所以只需使用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 之类的便利。

所以它可以通过聚合框架来完成,甚至可以通过合并“集合”结果的并行查询来完成。但是,虽然聚合框架可能比在外部合并结果集做得更好,但最好的结果总是来自首先计算边界。

【讨论】:

  • 太棒了!需要一点时间来制定你的解决方案......似乎很有希望:D
  • 在这种情况下使用两阶段聚合看起来最好
【解决方案2】:

如果其他人看到这个,从 mongo 版本 2.4 开始,您可以使用 $geoIntersects 查找 GeoJSON 对象的交集,它支持两个多边形的交集等类型。

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

有一篇很好的文章on this blog

【讨论】:

  • 其实没有。该问题要求发送“两个或多个多边形”并查看“那些”形状是否“插入”并包含在“该结果的交集”内找到的“点”。 $geoInsersects 用于搜索“使用”几何对象并查找“集合”中是否有任何“几何对象”实际上与查询中发出的对象“相交”。这是两个“完全”不同的东西。
猜你喜欢
  • 2016-06-11
  • 2012-10-17
  • 1970-01-01
  • 2012-06-19
  • 1970-01-01
  • 2012-08-23
  • 2016-12-08
  • 2012-12-27
  • 2017-02-18
相关资源
最近更新 更多