Dogevents – wyszukiwanie wydarzeń wg lokalizacji
Jedną z głównych funkcjonalności w projekcie Dogevents jest wyszukiwanie wydarzeń wg lokalizacji. MongoDB natywnie udostępnia taką funkcjonalność, należy tylko posiadać dane geolokalizacyjne w odpowiednim formacie, przygotować odpowiedni indeks i wywołać odpowiednie zapytanie.
Format danych
- tablicy: [54.4760932,18.5446327]
- dokumentu, np.: { lat: 54.4760932, lng: 18.5446327 }
"place": {
"name": "Psia Kość - szkolenie psów w Skoczowie",
"location": {
"city": "Skoczów",
"country": "Poland",
"latitude": 49.80972,
"longitude": 18.79726,
"street": "Wiejska 2",
"zip": "43-430"
},
"id": "519318824878019"
}
i przy próbie założenia wymaganego indeksu otrzymywałem błąd związany z brakiem możliwości rozpoznania danych lokalizacyjnych.
Transformacja danych
public class Coordinates
{
public double lng { get; set; }
public double lat { get; set; }
}
public class Location
{
public string City { get; set; }
public string Country { get; set; }
//For MongoDB geospatial search
public Coordinates Coordinates { get; set; }
public float Latitude { get; set; }
public float Longitude { get; set; }
public string Street { get; set; }
public string Zip { get; set; }
public Location()
{
this.Coordinates = new Coordinates();
}
}
Aby dane zostały wprowadzone do nowej właściwości Coordinates dodałem metodę, która jest wołana w momencie deserializacji:
[OnDeserialized]
public void OnDeserialized(StreamingContext context)
{
if (this.Place?.Location != null)
{
this.Place.Location.Coordinates.lat = this.Place.Location.Latitude;
this.Place.Location.Coordinates.lng = this.Place.Location.Longitude;
}
}
Jest to trochę mało eleganckie wyjście i powoduje duplikowanie danych. Ale chciałem na szybko uzyskać działający efekt. Na pewno jest to miejsce do optymalizacji, transformacji modelu. Końcowy dokument przyjął następującą formę:
"Place" : {
"Name" : "Ośrodek Wypoczynkowy Omega",
"Location" : {
"City" : "Przywidz",
"Country" : "Poland",
"Coordinates" : {
"lng" : 18.326669692993164,
"lat" : 54.193641662597656
},
"Latitude" : 54.193641662597656,
"Longitude" : 18.326669692993164,
"Street" : "Wczasowa 11",
"Zip" : "83-047"
}
},
Geospatial indeks
db.Events.createIndex({ "Place.Location.Coordinates":"2d" })
Przykładowe zapytanie
db.Events.find({
"Place.Location.Coordinates": {
$near: {
$geometry: {
type: "Point",
coordinates: [18.3737986, 54.5792772]
},
$maxDistance: 50 * 1000
}
}
}).pretty()
Koordynaty muszą zostać podane w postaci [długość_geograficzna (lng), szerokość_geograficzna (lat)]. Możemy określić maksymalny dystans (w metrach) jak również minimalny poprzez wskazane $minDistance.
Podsumowując. W bardzo prosty sposób możemy dodać do aplikacji funkcjonalność, która w połączeniu z bieżącą lokalizacją użytkownika umożliwi dostarczanie interesujących wydarzeń w w jego okolicy. Nie spodziewałem się tak szybkiego rozwiązania tego problemu. Jedynym z jakim się spotkałem to w dużej mierze brak danych lokalizacyjnych lub wpisanie samego miasta jako lokalizacji wydarzenia. Także wynik końcowy jest w dużej mierze zależny od osoby tworzącej wydarzenie.