2012-10-15 8 views
5

Come eseguire una query di intersezione o sovrapposizione nella shell di mongo: quali cerchi si sovrappongono alla mia area di ricerca? Within si riferiscono solo alla posizione centrale ma non includono il raggio degli altri cerchi nella portata cercata.Come trovare tutti i cerchi sovrapposti dal raggio del cerchio centrale?

Mongo:

# My bad conception: 
var search = [[30, 30], 10] 
db.places.find({circle : {"$within" : {"$center" : [search]}}}) 

Ora posso ottenere solo questo circoli all'interno punto centrale si trova nella zona cercato di circolo:

Rubino:

# field :circle, type: Circle # eg. [ [ 30, 30 ], 10 ] 
field :radius, type: Integer 
field :location, :type => Array, :spatial => true 
spatial_index :location 

Places.within_circle(location: [ [ 30, 30 ], 10 ]) 

# {"$query"=>{"location"=>{"$within"=>{"$center"=>[[30, 30], 10]}}} 

ho creato i dati di esempio con posizione aggiuntiva (indice speciale) e raggio invece cerchio perché il cerchio non è supportato da mongodb geo index:

{ "_id" : 1, "name" : "a", "circle" : [ [ 5, 5 ], 40 ], "latlng" : [ 5, 5 ], "radius" : 40 } 
{ "_id" : 2, "name" : "b", "circle" : [ [ 10, 10 ], 5 ], "latlng" : [ 10, 10 ], "radius" : 5 } 
{ "_id" : 3, "name" : "c", "circle" : [ [ 20, 20 ], 5 ], "latlng" : [ 20, 20 ], "radius" : 5 } 
{ "_id" : 4, "name" : "d", "circle" : [ [ 30, 30 ], 50 ], "latlng" : [ 30, 30 ], "radius" : 50} 
{ "_id" : 5, "name" : "e", "circle" : [ [ 80, 80 ], 30 ], "latlng" : [ 80, 80 ], "radius" : 30} 
{ "_id" : 6, "name" : "f", "circle" : [ [ 80, 80 ], 20 ], "latlng" : [ 80, 80 ], "radius" : 20} 

desiderata risultato della query:

{ "_id" : 1, "name" : "a", "circle" : [ [ 5, 5 ], 40 ], "latlng" : [ 5, 5 ], "radius" : 40 } 
{ "_id" : 3, "name" : "c", "circle" : [ [ 20, 20 ], 5 ], "latlng" : [ 20, 20 ], "radius" : 5 } 
{ "_id" : 4, "name" : "d", "circle" : [ [ 30, 30 ], 50 ], "latlng" : [ 30, 30 ], "radius" : 50} 
{ "_id" : 5, "name" : "e", "circle" : [ [ 80, 80 ], 30 ], "latlng" : [ 80, 80 ], "radius" : 30} 

soluzione qui di seguito presuppone che ricevo tutte le righe e poi filtrare sul lato rubino il mio raggio ma restituisce solo:

{ "_id" : 4, "name" : "d", "circle" : [ [ 30, 30 ], 50 ], "latlng" : [ 30, 30 ], "radius" : 50} 
+0

Penso che si desidera tornare "a" , "c" e "d". "e" non si sovrappone alla tua cerchia. –

+0

Non ho potuto verificare il mio codice la prima volta che ho risposto. Controllato e riparato ora. Puoi vedere da solo. Come disse Asya Kamsky, ti aspetti solo a, c, d. Altrimenti le informazioni che ci hai fornito sono sbagliate. – oldergod

+0

In realtà ho fatto un errore alla "e". Entrambe le soluzioni sono buone, ma ora vedo che per il momento attuale userò il rubino. Ho paura che su dischi di dimensioni maggiori il mio programma potrebbe non funzionare troppo velocemente, quindi ho chiesto anche l'approccio in mongo. Grazie! – roza

risposta

5

io non sono a conoscenza con mongodb ma presumo che in [[x, y], r] valori significa

x: valore del centro sull'asse x. y: valore del centro sull'asse y. r: raggio del cerchio.

Supponiamo di avere un cerchio S che è la tua ricerca e un cerchio casuale A. Quindi puoi calcolare la distanza tra il centro di entrambi i cerchi (S.center e A.center) e vedere se è inferiore a entrambi Raggio di cerchi aggiunto (Sr + Ar).

def distance_between(a, b) 
    ((b.first - a.first)**2 + (b.last - a.last)**2)**0.5 
end 

elements = [{ _id: 1, name: "a", circle: [ [ 5, 5 ], 40 ] }, 
      { _id: 2, name: "b", circle: [ [ 10, 10 ], 5 ] }, 
      { _id: 3, name: "c", circle: [ [ 20, 20 ], 5 ] }, 
      { _id: 4, name: "d", circle: [ [ 30, 30 ], 50 ] }, 
      { _id: 5, name: "e", circle: [ [ 80, 80 ], 30 ] }, 
      { _id: 6, name: "f", circle: [ [ 80, 80 ], 20 ] }] 
search = [[30, 30], 10] 

elements.select do |elem| circle = elem[:circle] 
    distance_between(circle.first, search.first) <= circle.last + search.last 
end 

#{:_id=>1, :name=>"a", :circle=>[[5, 5], 40]} 
#{:_id=>3, :name=>"c", :circle=>[[20, 20], 5]} 
#{:_id=>4, :name=>"d", :circle=>[[30, 30], 50]} 
3

Sfortunatamente non è attualmente possibile in mongo interrogare direttamente su oggetti sovrapposti, solo punti all'interno di oggetti.

La risposta di @ oldergod descrive l'algoritmo per calcolare se due cerchi si sovrappongono.

Ecco un work-around nella shell sulla base di tale calcolo:

function distance(a, b) { 
    return Math.pow(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2), 0.5); 
} 

sui dati del campione inserito nella collezione 'cerchio':

> db.circle.find().forEach(
    function(c) { 
     if ((distance(c.latlng, search.latlng) < c.radius + search.radius)) 
      { 
       print(c.name); 
      } 
    }) 
a 
c 
d 
> 
+0

Si prega di notare che a partire dal 2.4 (Marzo 2013) L'operatore $ geoIntersects è disponibile a fornire questa funzionalità per gli indici GeoJSON e 2dSphere. –