Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Ricerche geografiche

Su MongoDB è possibile memorizzare dati geografici utilizzando coordinate bidimensionali o il formato GeoJSON: ecco come fare, e come realizzare query su questo tipo di dati.
Su MongoDB è possibile memorizzare dati geografici utilizzando coordinate bidimensionali o il formato GeoJSON: ecco come fare, e come realizzare query su questo tipo di dati.
Link copiato negli appunti

Uno dei motivi del grande successo di tablet e smartphone è dato dalla possibilità di implementare app che possano sfruttare la conoscenza della posizione
dell’utente per fare ricerche mirate, fornire informazioni più precise o anche semplicemente realizzare logiche basate sulle distanze. L’importanza di
questo tipo di informazione è tale che la geolocalizzazione è stata introdotta nello standard HTML5, per cui è possibile accedere alla
posizione utente persino da JavaScript.

Memorizzazione di dati geografici

A titolo esemplificativo, un’applicazione potrebbe mostrare all’utente la distanza del ristorante più vicino. Per fare ciò, essa dovrebbe memorizzare la
posizione di tutti i ristoranti (se non quelli di tutto il mondo, almeno quelli della regione geografica dei propri utenti). MongoDB permette due tipi di
strutture dati per i dati geografici:

  1. il formato GeoJSON;
  2. coordinate bidimensionali, utilizzando coppie di coordinate [x, y].

Con il primo si possono rappresentare diversi tipi di oggetti (punti, linee, poligoni) ed è la scelta raccomandata per rappresentare coordinate geografiche
di tipo sferico (latitudine e longitudine), mentre il secondo è raccomandato quando si ha a che fare con un piano euclideo.

Utilizzo di GeoJSON con coordinate sferiche

Vediamo subito un esempio. Il comando che segue aggiunge un oggetto alla collezione ristoranti, che rappresenta un ristorante completo di
coordinate geografiche.

db.ristoranti.insert( {
      posizione : { type: "Point", coordinates: [48.8837959, 2.3277204]},
      nome: "La Coupole",
      località: "Parigi"
})

Il campo posizione rappresenta la posizione geografica in formato GeoJSON. In questo caso la posizione è stata indicata come un singolo punto (Point).

Per potere effettuare interrogazioni, è ora necessario creare un apposito indice per questo campo. Per i dati di tipo GeoJSON l’indice da creare è di tipo 2dsphere. La sintassi è la seguente:

db.ristoranti.ensureIndex( { posizione: "2dsphere" } );

Interrogazioni su campi GeoJSON

Ora possiamo interrogare il nostro indice, per esempio per conoscere i ristoranti più vicini alla nostra posizione, nel raggio di un chilometro:

db.ristoranti.find( { posizione :  { $near :
                           { $geometry :
                              { type : "Point" , coordinates : [48.882, 2.325] } ,
                              $maxDistance : 1000 } } } )

L’operatore $near seleziona e ordina in ordine crescente di distanza gli oggetti della collezione più vicini al
punto specificato. Si tratta dunque di un operatore molto potente, che innanzitutto ci toglie la necessità di implementare algoritmi di calcolo delle
distanze su superfici sferiche, e poi che, grazie all’indicizzazione, ottimizza anche la quantità di oggetti della collezione che devono essere analizzati.

Un altro operatore supportato è l’operatore di inclusione, $geoWithin. Questo operatore permette
di selezionare gli oggetti che si trovano entro un certo poligono; ad esempio:

db. ristoranti.find( { posizione : { $geoWithin :
                    { $geometry :  { type : "Polygon" ,
                        coordinates : [ [
                                          [ 48 , 2 ] ,   [ 49 , 2 ] ,   [ 49, 3 ] ,  [ 48 , 2.9 ], [48, 2]
                                        ] ]
                } } } } )

Questa volta le coordinate specificate rappresentano i vertici del poligono in cui vogliamo cercare i ristoranti. Vediamo anche che abbiamo specificato nel
campo type che indicheremo un poligono. Esso, ovviamente, deve essere chiuso, ossia il primo punto deve essere uguale all’ultimo, altrimenti
MongoDB restituirà un errore. Se la nostra collezione, anziché punti (type: "Point") contiene dei poligoni (type:
"Polygon"
) nel campo posizione, verranno considerati solamente i poligoni che stanno interamente nel poligono specificato nella
query. Specificando l’operatore di intersezione $geoIntersect al posto di $geoWithin nel codice precedente, si ottengono invece i poligoni che hanno un’intersezione non vuota con il poligono usato
nella query.

Geometria euclidea

Se il nostro sistema di coordinate è basato su coordinate del piano euclideo (perché per esempio la nostra applicazione utilizza un sistema di mappe
piane), a differenza dell’approccio che abbiamo visto sopra, dobbiamo usare:

  • coordinate non in formato GeoJSON, bensì rappresentate da un semplice array [x, y];
  • un indice 2d.

Vediamo subito un esempio. Inseriamo un elemento e creiamo il nostro indice, stavolta di tipo 2d:

db.uffici.insert( {
      posizione : [10, 5],
      nome: "Quartier generale"
});
db. uffici.ensureIndex( { posizione: "2d" } );

A questo punto, per effettuare le query di prossimità, la sintassi è analoga:

db.uffici.find( {
       posizione :  { $near : [11,2], $maxDistance: 5}
});

Le query di inclusione possono essere effettuate utilizzando l’operatore $geoWithin, e si
possono utilizzare tre forme:

  • box
    : rettangolo, in cui si specificano i due vertici in basso a sinistra, ed in alto a destra;
  • center
    : cerchio, in cui si specificano centro e raggio;
  • poligono
    : poligono, in cui si specificano le coordinate di tutti i vertici.

Proviamo quindi a cercare tutti gli uffici che si trovano in un cerchio di raggio 7 dal punto [5,3]:

db.uffici.find( {  posizione :  { $geoWithin:  { $center: [ [ 5, 3], 7 ] } }})

Le query di intersezione non sono supportate
da questo tipo di indice. Perciò, se esse sono importanti per la nostra applicazione, bisogna prendere in considerazione la possibilità di migrare a
GeoJSON.

Per ulteriori dettagli sulle ricerche geografiche rimandiamo alla guida ufficiale, in particolare alla sezione relativa agli operatori.

Ti consigliamo anche