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'用於搜索「使用」幾何對象,並查找「集合」中的任何「幾何對象」實際上是否與查詢中發出的對象「交叉邊界」。這是兩個「完全」不同的東西。 –

相關問題