2012-10-15 16 views
5

Jak wykonać zapytanie przecięcia lub nakładania w powłoce Mongo - jakie kółka pokrywają się z moim obszarem wyszukiwania? Within dotyczą tylko położenia środkowego, ale nie obejmują promienia pozostałych okręgów w zakresie objętym zasięgiem.Jak znaleźć wszystkie nakładające się koła z promienia środkowego koła?

Mongo:

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

Teraz mogę uzyskać tylko to kręgi w obrębie centralnego punktu leży w przeszukiwanego obszaru okręgu:

Ruby:

# 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]}}} 

utworzonego przykładowe dane z dodatkowych lokalizacji (specjalny indeks) i promień zamiast okręgu, ponieważ koło nie jest obsługiwane przez wskaźnik geograficzny mongodb:

{ "_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} 

Pożądany wynik zapytania:

{ "_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} 

Rozwiązanie poniżej zakłada, że ​​mam wszystkie wiersze, a następnie filtrować rubin bocznej moim promieniu ale zwraca tylko:

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

Myślę, że chcesz z powrotem „a” , "c" i "d". "e" nie pokrywa się z kręgu. –

+0

Nie mogłem sprawdzić mojego kodu, gdy pierwszy raz odpowiedziałem. Sprawdziłem i naprawiłem teraz. Możesz zobaczyć sam. Jak powiedziała Asya Kamsky, oczekujesz tylko a, cid. W przeciwnym razie informacje, które nam przekazałeś, są błędne. – oldergod

+0

Właściwie popełniłem błąd na "e". Oba rozwiązania są dobre, ale teraz widzę, że na obecną chwilę użyjemy ruby. Obawiam się, że przy większych rozmiarach mój program może nie działać zbyt szybko, więc zapytałem także o podejście w Mongo. Dziękuję Ci! – roza

Odpowiedz

5

nie znam z mongodb, ale zakładam, że w [[x, y], r] wartości oznaczają

x: wartość centrum na osi x. y: wartość centrum na osi y. r: promień okręgu.

Say masz Circle S, który jest wyszukiwanie i bezładny krąg A. Następnie można calcule odległość pomiędzy centrum oba okręgi (S.center i A.center) i sprawdzić, czy jest gorsze zarówno dodano promień koła (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

Niestety w Mongo nie ma obecnie możliwości bezpośredniego zapytania o nakładające się obiekty, tylko punkty w obrębie obiektów.

@ oldergod's answer opisuje algorytm do obliczenia, czy dwa okręgi pokrywają się.

Oto obejście w powłoce na podstawie tych obliczeń:

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

Na swoich przykładowych danych włożona do zbierania „koła”:

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

Uwaga: od 2.4 (marzec 2013 r.) Operator $ geoIntersects udostępnia tę funkcję dla indeksów GeoJSON i 2dSphere. –

Powiązane problemy