Così guardando questo con una mente fresca la risposta mi sta fissando in faccia. La cosa fondamentale che hai già detto è che vuoi trovare "l'intersezione" di due query in una singola risposta.
Un altro modo per osservare questo è che si desidera che tutti i punti vincolati dalla prima query siano "input" per la seconda query e così via come richiesto. Questo è essenzialmente ciò che fa un incrocio, ma la logica è in realtà letterale.
Quindi utilizzare lo aggregation framework per concatenare le query corrispondenti. Per un semplice esempio, prendere in considerazione i seguenti documenti:
{ "loc" : { "type" : "Point", "coordinates" : [ 4, 4 ] } }
{ "loc" : { "type" : "Point", "coordinates" : [ 8, 8 ] } }
{ "loc" : { "type" : "Point", "coordinates" : [ 12, 12 ] } }
e il gasdotto di aggregazione incatenato, solo due domande:
db.geotest.aggregate([
{ "$match": {
"loc": {
"$geoWithin": {
"$box": [ [0,0], [10,10] ]
}
}
}},
{ "$match": {
"loc": {
"$geoWithin": {
"$box": [ [5,5], [20,20] ]
}
}
}}
])
Quindi, se si considera che logicamente, il primo risultato sarà trovare i punti che cadono entro i limiti della casella iniziale o dei primi due elementi. Questi risultati vengono quindi interpretati dalla seconda query e poiché i nuovi limiti di casella iniziano da [5,5]
che esclude il primo punto. Il terzo punto era già stato escluso, ma se le restrizioni sulla scatola fossero state invertite, il risultato sarebbe stato lo stesso solo per il documento centrale.
Come funziona in modo del tutto unico per l'operatore $geoWithin
interrogazione rispetto a varie altre funzioni di geo:
$geoWithin non richiede un indice geospaziale.Tuttavia, un indice geospaziale migliorerà le prestazioni della query. Entrambi gli indici geospaziali supportati da 2dsphere e 2d supportano $geoWithin.
Quindi i risultati sono buoni e cattivi. In questo modo è possibile eseguire questo tipo di operazione senza un indice, ma è negativo perché una volta che la pipeline di aggregazione ha modificato i risultati della raccolta dopo la prima operazione di query, non è possibile utilizzare altri indici. Pertanto, qualsiasi vantaggio in termini di prestazioni di un indice viene perso in seguito alla fusione dei risultati "impostati" da qualsiasi elemento dopo l'iniziale Polygon/MultiPolygon come supportato.
Per questo motivo mi raccomando ancora che si calcolano i limiti di intersezione "al di fuori" della query rilasciato a MongoDB. Anche se il framework di aggregazione può fare ciò a causa della natura "concatenata" della pipeline e anche se le intersezioni risultanti diventeranno sempre più piccole, la migliore prestazione è una singola query con i limiti corretti che può utilizzare tutti i vantaggi dell'indice.
Ci sono vari metodi per farlo, ma per riferimento qui è un'implementazione utilizzando la libreria JSTS, che è una porta JavaScript della famosa libreria JTS per Java. Ci possono essere altri o altre porte lingua, ma questo ha semplice analisi GeoJSON e costruito in metodi per tali cose come ottenere i limiti di intersezione:
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();
}
);
});
});
Utilizzando la piena GeoJSON "Poligono" rappresentazioni là come questo si traduce in ciò che JTS può capire e lavorare con È probabile che qualsiasi input che potresti ricevere per un'applicazione reale sia in questo formato, piuttosto che applicare comodità come $box
.
Così può essere fatto con il framework di aggregazione, o anche con le query parallele che uniscono il "set" dei risultati. Ma mentre il framework di aggregazione può fare meglio di unire all'esterno un insieme di risultati, i risultati migliori verranno sempre dal calcolo dei limiti.
Questo aiuto? -http: //docs.mongodb.org/manual/reference/operator/query/geoIntersects/#example. Includi i documenti di esempio nella tua collezione che descrivono le coordinate. – BatScream
@BatScream Il documento di esempio è la seguente: { "_id": "35004", "città": "ACMAR", "loc": [ -86,51557, 33,584,132 mila ], "pop" : 6055, "stato": "AL" } – Viraj
@BatScream Grazie per la risposta. In realtà il link doc mongodb che hai fornito fornisce risultati basati sul poligono. Quello che sto cercando per qualcosa di simile. 1. Prima la query ottiene i risultati all'interno della casella A. 2. Secondo la query ottiene i risultati all'interno della casella B. 3. Terzo la query restituisce i risultati comuni a entrambi i riquadri A e B, il che significa che la query fornisce l'intersezione a due scatole o forse in generale due poligoni: D. C'è un modo per farlo? – Viraj