左右的时间内结果用清新的头脑看着这个问题,答案就是把我凝视在脸上。你已经说过的关键是你想在一个响应中找到两个查询的“交集”。
查看此问题的另一种方法是,您希望由第一个查询绑定的所有点随后将作为第二个查询的“输入”,并根据需要依此类推。这基本上是一个交集,但逻辑实际上是字面的。
所以只需使用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