Zakładając, że już pracowałeś nad działaniem na danych zdarzenia, gdy je otrzymujesz i masz pod ręką (jeśli nie, to jest to kolejne pytanie, ale spójrz na kursory konfigurowalne ), powinieneś mieć obiekt z tymi danymi, o który chcesz zapytać użytkowników.
Nie dotyczy to zatem oceny JavaScript z $where
, ponieważ nie może uzyskać dostępu do danych zapytania zwróconych przez $near
w każdym razie operacja. Zamiast tego chcesz $geoNear
z ram agregacji. Może to rzutować „odległość” znalezioną na podstawie zapytania i umożliwić na późniejszym etapie „filtrowanie” wyników względem wartości zapisanej przez użytkownika pod kątem maksymalnej odległości, jaką chcą przebyć do opublikowanych wydarzeń:
// Represent retrieved event data
var eventData = {
eventLocation: {
latlong: [long,lat]
}
};
// Find users near that event within their stored distance
User.aggregate(
[
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": eventData.eventLocation.latlong
},
"distanceField": "eventDistance",
"limit": 100000,
"spherical": true
}},
{ "$redact": {
"$cond": {
"if": { "$lt": [ "$eventDistance", "$maxDistance" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
]
function(err,results) {
// Work with results in here
}
)
Teraz musisz być ostrożny z zwracaną liczbą, ponieważ wydaje się, że przechowujesz w „starszych parach współrzędnych” zamiast w GeoJSON, wtedy odległość zwrócona z tej operacji będzie wyrażona w radianach, a nie w standardowej odległości. Zakładając więc, że przechowujesz obiekty użytkownika w milach lub kilometrach, musisz obliczyć za pomocą wzoru podanego w instrukcji pod "Oblicz odległości przy użyciu geometrii sferycznej" jak wspomniano w instrukcji.
Podstawą jest to, że musisz podzielić przez promień równikowy Ziemi, który wynosi 3963,2 mil lub 6378,1 km, aby przekonwertować je w celu porównania z tym, co zapisałeś.
Alternatywą jest przechowywanie w GeoJSON, gdzie istnieje spójny pomiar w metrach.
Zakładając, że „kilometry” linia „jeśli” staje się:
"if": { "$lt": [
"$eventDistance",
{ "$divide": [ "$maxDistance", 6,378.1 ] }
]},
Aby wiarygodnie porównać zapamiętaną wartość kilometra z otrzymanym wynikiem w radianach.
Inną rzeczą, o której należy pamiętać, jest to, że $geoNear
ma domyślny "limit" 100 wyników, więc musisz "podkręcić" argument "limit" do liczby, aby oczekiwani użytkownicy mogli się dopasować. Możesz nawet chcieć to zrobić w "listach zakresów" identyfikatorów użytkowników dla naprawdę dużego systemu, ale możesz zrobić tak duży, jak pozwala na to pamięć w ramach pojedynczej operacji agregacji i ewentualnie dodać allowDiskUse
w razie potrzeby.
Jeśli nie dostroisz tego parametru, zostanie zwróconych tylko najbliższe 100 wyników ( default ), które mogą nie pasować nawet do następnej operacji filtrowania tych „w pobliżu” zdarzenia, od którego chcesz zacząć. Kieruj się jednak zdrowym rozsądkiem, ponieważ z pewnością masz maksymalną odległość, aby nawet odfiltrować potencjalnych użytkowników, a to również można dodać do zapytania.
Jak wspomniano, chodzi o zwrócenie odległości do porównania, więc następnym etapem jest $redaguj
operacja, która może dopasować własną wartość „odległość podróży” użytkownika do zwróconej odległości od zdarzenia. Wynik końcowy daje tylko tym użytkownikom, którzy znajdują się we własnym zakresie ograniczenia odległości od wydarzenia, którzy kwalifikują się do powiadomienia.
Taka jest logika. Projektujesz odległość od użytkownika do zdarzenia, a następnie porównujesz z zapisaną przez użytkownika wartością odległości, jaką są gotowi do przebycia. Brak JavaScript i wszystkie natywne operatory, które sprawiają, że jest dość szybki.
Jak wspomniano w opcjach i ogólnym komentarzu, naprawdę sugeruję użycie indeksu „2dsphere” do dokładnego obliczania odległości sferycznej, a także konwersji na pamięć GeoJSON do przechowywania współrzędnych w bazie danych Obiekty, ponieważ oba są ogólnymi standardami, które dają spójne wyniki.