当前位置: 首页 > 知识库问答 >
问题:

MongoDB-两多边形的地理空间相交

龙隐水
2023-03-14

我们是否可以使用符合以下条件的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 ] ] } }
} )

共有1个答案

王飞虎
2023-03-14

所以,用一个新的头脑来看待这个问题,答案就在我面前。您已经说明的关键是,您希望在单个响应中找到两个查询的“交集”。

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

因此,只需使用聚合框架将匹配的查询链接起来即可。对于一个简单的示例,请考虑以下文档:

{ "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] ]
            }
        }
    }}
])

出于这个原因,我仍然建议您计算发出给MongoDB的查询“外部”的交集边界。尽管由于管道的“链式”性质,聚合框架可以做到这一点,而且产生的交集会越来越小,但最好的性能是一个具有正确边界的查询,它可以使用索引的所有优点。

有各种方法可以实现这一点,但这里有一个使用JSTS库的实现供参考,它是流行的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之类的便利。

 类似资料:
  • 如何从多个地理位置(长,晚值)创建多边形地理围栏。也可以在Android上跟踪用户进入或退出该地理区域的情况。

  • 我有一个“SpatialPolygons”对象,我想在@hole==FALSE处对多边形进行子集,并创建一个新对象。 使用下面的代码,一次可以预测得到1个多边形(如果@hole==TRUE,则没有),但我无法从对象中分割多个多边形。 我认为我的问题在于我不知道如何“一般”引用第二个列表,即从列表(Polygon)中获取项目,其中@孔==FALSE。将第二个[[]]留空不起作用。 附言:抱歉,没有可

  • 根据API文件,只允许圆形土工篱笆: 但我有4个位置,代表矩形的4个角,我想让我的地理围栏是那个矩形。 我想避免建立我的自定义位置监控服务的解决方案扩展的功能监测地理围栏,因为我认为这类服务是CPU和功耗消耗。 谢谢,

  • 我有一个包含多边形的json,这些多边形表示一个国家中所有城市(总共78个)的分隔符。例如: 有没有什么方法可以用一个查询将所有城市的结果分组,或者我必须查询数据库78次才能获得每个城市的计数?

  • 我试图从顶点位置创建一组多边形,保存在X,Y格式。 下面是我的数据的一个例子——每行代表一个多边形的顶点。多边形是正方形 我正在使用,因此我的数据需要在列表中。所以我创建了一个循环来尝试从矩阵中将我的数据转换为列表格式。 我创建了一个循环,遵循我在这个网站上的其他一些问题中找到的代码。我突破了每一步,试图理解为什么我只有一个多边形作为输出,即使我有2组点。 你能帮我理解我如何调整代码写出两个多边形

  • 有没有人知道如何在Android中创建一个多边形的地理围栏?我知道Android支持圆形(即lat/long+radius)地理围栏,但我需要对它们的边界进行更精确的控制。