Vir*_*raj 8 javascript geospatial mongodb mongodb-query aggregation-framework
有没有什么方法可以使用符合以下条件的mongodb地理空间查询来查询和获取位置数据?
例如,下面我们可以在查询输出中只获得黄色区域内的那些位置,这些位置实际上是紫色和红色几何对象[多边形]的公共区域?

我到目前为止对mongodb文档的研究
这提供了一个或多个多边形内的结果[我正在寻找这些单个多边形结果作为输出的交集]
用例
db.places.find( {
loc: { $geoWithin: { $box: [ [ 0, 0 ], [ 100, 100 ] ] } }
} )
Run Code Online (Sandbox Code Playgroud)
上面的查询提供了一个矩形几何区域内的结果[我正在寻找两个这样的单个查询共有的位置]
db.places.find( {
loc: { $geoWithin: { $box: [ [ 0, 0 ], [ 100, 100 ] ] } }
} )
db.places.find( {
loc: { $geoWithin: { $box: [ [ 50, 50 ], [ 90, 120 ] ] } }
} )
Run Code Online (Sandbox Code Playgroud)
因此,以一种清新的头脑看待这个问题,答案就是盯着我.您已经说过的关键是您希望在单个响应中找到两个查询的"交集".
另一种看待这种情况的方法是,您希望第一个查询绑定的所有点然后为第二个查询"输入",依此类推.这实际上是一个交集所做的,但逻辑实际上是文字的.
因此,只需使用聚合框架链接匹配的查询.举一个简单的例子,请考虑以下文档:
{ "loc" : { "type" : "Point", "coordinates" : [ 4, 4 ] } }
{ "loc" : { "type" : "Point", "coordinates" : [ 8, 8 ] } }
{ "loc" : { "type" : "Point", "coordinates" : [ 12, 12 ] } }
Run Code Online (Sandbox Code Playgroud)
和链式聚合管道,只有两个查询:
db.geotest.aggregate([
{ "$match": {
"loc": {
"$geoWithin": {
"$box": [ [0,0], [10,10] ]
}
}
}},
{ "$match": {
"loc": {
"$geoWithin": {
"$box": [ [5,5], [20,20] ]
}
}
}}
])
Run Code Online (Sandbox Code Playgroud)
因此,如果您从逻辑上考虑,第一个结果将找到落在初始框或前两个项的范围内的点.然后,第二个查询对这些结果起作用,并且由于新的框边界开始,[5,5]因此排除了第一个点.第三点已被排除,但如果方框限制被颠倒,那么结果将只是相同的中间文件.
$geoWithin与其他各种地理函数相比,它对查询运算符的工作方式非常独特:
$ geoWithin不需要地理空间索引.但是,地理空间索引将提高查询性能.无论2dsphere和二维地理空间索引支持$ geoWithin.
所以结果既好又坏.很好,你可以在没有索引的情况下进行这种类型的操作,但是很糟糕,因为一旦聚合管道在第一次查询操作之后改变了收集结果,就不能再使用索引了.因此,在支持初始Polygon/MultiPolygon之后合并"set"结果时,索引的任何性能优势都会丢失.
出于这个原因,我仍然建议你计算发给MongoDB的查询的"外部"的交集边界.尽管聚合框架可以通过管道的"链式"特性来实现这一点,即使生成的交叉点会变得越来越小,但最佳性能是具有正确边界的单个查询,可以使用所有索引优势.
有各种方法可以做到这一点,但这里的参考是使用JSTS库的实现,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();
}
);
});
});
Run Code Online (Sandbox Code Playgroud)
使用完整的GeoJSON"Polygon"表示,这可以转换为JTS可以理解和使用的内容.对于真实应用程序可能会收到的任何输入都可能是这种格式,而不是应用诸如此类的便利$box.
因此,可以使用聚合框架,甚至是并行查询来合并结果的"集合".但是虽然聚合框架可能比在外部合并结果集更好,但最好的结果总是来自计算边界.