左右的時間內結果用清新的頭腦看着這個問題,答案就是把我凝視在臉上。你已經說過的關鍵是你想在一個響應中找到兩個查詢的「交集」。
查看此問題的另一種方法是,您希望由第一個查詢綁定的所有點隨後將作爲第二個查詢的「輸入」,並根據需要依此類推。這基本上是一個交集,但邏輯實際上是字面的。
所以只需使用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不需要地理空間索引。但是,地理空間索引將提高查詢性能。 2dsphere和2d地理空間索引都支持$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
。
因此可以使用聚合框架,甚至並行查詢來合併結果的「集合」。但是,雖然聚合框架可能比從外部合併結果集更好,但最好的結果總是來自先計算邊界。
這有幫助嗎? -http://docs.mongodb.org/manual/reference/operator/query/geoIntersects/#example。請在您的收藏中包含描述座標的示例文檔。 – BatScream
@BatScream 的示例文檔如下: { 「_id」: 「35004」, 「城市」: 「ACMAR」, 「LOC」:[ -86.51557, 33.584132 ], 「流行」 :6055, 「狀態」:「AL」 } – Viraj
@BatScream感謝您的迴應。實際上,您提供的mongodb文檔鏈接提供了基於多邊形的結果。我在尋找這樣的東西。 1.首先查詢得到方框A內的結果。 2.其次查詢得到方框B內的結果。 3.第三查詢輸出對於方框A和B都通用的結果,這意味着查詢提供了與兩個方向的交集盒子或者通常可以是兩個多邊形:D。有沒有辦法做到這一點? – Viraj