Armazenando dados de geoposicionamento com Google Maps e MongoDB
Veja neste artigo como desenvolver uma aplicação baseada em dados geográficos usando a API do Google Maps e o MongoDB. A aplicação consiste de uma página na qual vamos inserir a localização de passageiros de taxi e uma outra onde veremos um mapa
O Google Maps API permite utilizar a maioria das funcionalidades disponíveis no site do Google Maps para criar aplicações com a capacidade, entre outras coisas, de recuperar a latitude e longitude de um endereço, adicionar um marcador em um mapa, criar uma área (um polígono ou um círculo) e calcular a distância entre dois pontos.
O MongoDB, cujo nome vem de humongous uma gíria americana para descrever algo muito grande, foi criado em 2009 e atualmente é o banco de dados do tipo NoSQL mais usado no mundo. Seu código é aberto e pode ser utilizado em distintas plataformas e clientes de linguagem. Além disso, o MongoDB utiliza JSON para descrever e armazenar documentos.
Primeiramente, vamos criar a página HTML para inserir os dados do passageiro. Essa página receberá o nome e o endereço do passageiro. O processo de descobrir a posição geográfica a partir do endereço é denominado geoposicionamento, e a API do Google Maps nos auxilia nesse processo.
Para utilizar a API do Google Maps, devemos ter um cadastro prévio no Google. Nessa página, podemos criar uma chave de acesso ao Google Maps API.
Tendo essa chave de acesso, vamos importar para a nova página os scripts do Google Maps API. Devemos adicionar o CSS, a biblioteca de jQuery e, principalmente, a API para a qual devemos passar a chave – coloque sua chame em - criada anteriormente, conforme explicado na Listagem 1.
<link href='http://fonts.googleapis.com/css?family=
Open+Sans:400,300,600,700,800'
rel='stylesheet' type='text/css'>
<script src="http://maps.googleapis.com/maps/api/js?key=
<CHAVE>&sensor=false"></script>
<script src="http://ajax.googleapis.com/ajax/libs/
jquery/2.1.1/jquery.min.js"></script>
Na Listagem 2 apresenta-se como criar a página usando geocodificação - em inglês geocoder -, que irá retornar valores de latitude e longitude a partir do endereço inserido em uma página – nesse caso, não apresentamos o código HTML, mas espera-se que haja das caixas de texto: location, que conterá o endereço do passageiro e user, que conterá o nome do passageiro. Os valores retornados por essa função serão enviados ao servidor Node.js – através de uma chamada GET -, que os inserirá no MongoDB apresentado mais adiante.
function getLatLong(){
var geo = new google.maps.Geocoder;
//valor vindo da caixa de texto chamada location
var address = $('#location').val();
var user = $('#user).val();
geo.geocode({'address':address},function(results, status){
if (status == google.maps.GeocoderStatus.OK) {
var lat = results[0].geometry.location.lat();
var lng = results[0].geometry.location.lng();
var latlng = new google.maps.LatLng(lat,lng);
var mapProp = {
center:latlng,
zoom:18,
mapTypeId:google.maps.MapTypeId.ROADMAP,
mapTypeControl: false
};
var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
var marker = new google.maps.Marker({
position: latlng,
map: map,
title:name
});
$.get( "http://localhost:1346?nome="+user+"&lat="+lat+"&lon="+lng, null);
} else {
//alert("O Geocoder falhou: " + status);
}
});
}
Para utilizar o MongoDB devemos previamente instalar esse gerenciador de documentos. Nesse artigo vamos utilizar Ubuntu, porém o MongoDB pode ser instalado também em outros Linux e no Windows. A Tabela 1 apresenta uma breve descrição da sequência de comandos que vamos utilizar para instalar o MongoDB.
Comando | Descrição |
---|---|
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 | Importar a chave pública do repositório do MongoDB |
echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list | Criar uma lista para o MongoDB |
sudo apt-get update | Atualizar o APT com o novo repositório e a nova lista |
sudo apt-get install -y mongodb-org | Instalar o MongoDB |
sudo service mongod start | Iniciar o MongoDB |
/var/log/mongodb/mongod.log | Verificar se o MongoDB foi iniciado com sucesso. Em caso positivo, a última linha do arquivo de log deve ser [initandlisten] waiting for connections on port 27017 |
mongo | Entra no shell |
use devmedia | Alterna para o banco de dados denominado devmedia |
O próximo passo é criar uma collection – que pode ser entendia com a correspondente da tabela nos bancos de dados baseados em SQL. Para criar essa collection, devemos entrar no console de comandos do MongoDB e executar os comandos da Listagem 3. O comando irá criar uma collection do tipo capped chamada passageiros, cujo tamanho máximo será 5242880 bytes. Essa coleção poderá receber uma quantidade imensa de dados simultâneos para escrita, leitura ou exclusão, pois esse tipo de coleção – do tipo capped -, atua como uma lista circular, na qual os dados podem ser escritos incessantemente, já que os valores mais antigos serão sobrescritos, se necessário, para manter o limite dentro do tamanho especificado. Este recurso é extremamente útil para registros de log, dados de streaming e aplicações em tempo real.
db.createCollection("passageiros", { capped : true,
size : 5242880, max : 5000 } )
Essa collection irá receber documentos JSON que vão representar a posição dos passageiros inseridas na Listagem 2. Através do da linha de comandos podemos inserir valores a essa collection, conforme ilustrado na Listagem 4. Essa inserção utilizar o padrão chamado GeoJSON para inserir a posição do passageiro recuperado na Listagem 3. Nesse exemplo criamos um ponto usando valores de latitude e longitude, contudo o GeoJSON permite criar também linhas e polígonos.
db.passageiros.insert(
{
_id: "P1",
"nome": "João da Silva",
"loc": {
type: "Point",
"coordinates": [125.6, 10.1]
}
}
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [125.6, 10.1]
},
"properties": {
"name": "João da Silva"
}
}
)
db.passageiros.find()
Na sequência vamos integrar o Google Maps API usando o driver de Node.js para MongoDB. Como explicado na Tabela 2, a primeira providência é instalar o Node.js e o driver chamado MongoJS.
Comando | Descrição |
---|---|
sudo apt-get install nodejs | Instalar o Node.js |
sudo apt-get install npm | Instalar o npm, o gerenciador de pacotes do Node.js |
npm install mongodb | Instalar o MongoJS |
npm install jquery | Instalar a integração de Node.js com JQuery |
nodejs inserir.js | Iniciar a execução do script de node.js |
Com o driver instalado, podemos criar um novo arquivo Node.js (para iniciar esse arquivo execute nodejs inserir.js) responsável por enviar as informações ao MongoDB, ou seja, recuperamos o nome do passageiro, sua latitude, sua longitude e através do driver as inserimos na collection passageiros. As primeiras linhas da Listagem 5 - como indicado pelos comentários – realiza a conexão com o MongoDB. Na sequência usando o cliente criado – chamado MongoClient, onde vamos criar um documento no formato JSON com os valores de nome, latitude e longitude e, finalmente, realizar a inserção no MongoDB.
var http = require('http');
var url = require('url');
http.createServer(function (req, res) {
var url_parts = url.parse(req.url, true);
var query = url_parts.query;
var latitude = query.lat;
var longitude = query.lon;
var usuario = query.nome;
// Retrieve
var MongoClient = require('mongodb').MongoClient;
//Conexão ao MongoDB
MongoClient.connect("mongodb://localhost:27017/devmedia", function(err, db) {
if(err) { return console.dir(err); }
//Escolher a collection passageiros
var collection = db.collection('passageiros');
var doc = {
'nome": usuario,
'loc': {
'type': 'Point',
'coordinates': [latitude, longitude]
}
collection.insert(doc , { w: 0 });
});}).listen(1346, '0.0.0.0');
console.log('Server running at http 0.0.0.0:1346:');
A próxima tarefa e criar uma página que apresente em um mapa as posições dos passageiros que foram inseridas anteriormente. A Listagem 6 apresenta a função recuperaPassageiros.js (para iniciar esse arquivo execute nodejs recuperaPassageiros.js), que também irá criar uma conexão com o MongoDB e definir a collection passageiros como alvo. Além disso, essa função executara um comando de find para buscar todas as localizações que estão armazenadas no nosso banco de dados. Finalmente, o resultado desse comando será uma lista chamada itens que será enviada a função apresentaLocalizacoes.
var http = require('http');
http.createServer(function (req, res) {
// Retrieve
var MongoClient = require('mongodb').MongoClient;
// Connect to the db
MongoClient.connect("mongodb://localhost:27017/devmedia", function(err, db) {
if(err) { return console.dir(err); }
var collection = db.collection('passageiros');
collection.find().toArray(function(err, docs){
res.writeHead(200, {
'Content-Type': 'text/html',
'Access-Control-Allow-Origin' : '*'});
var intCount = docs.length;
console.log(intCount);
if(intCount > 0){
res.write("[");
for(var i=0; i<intCount;i++){
var jsonText = JSON.stringify({nome: docs[i].properties
.name.toString(),lat:docs[i].geometry.coordinates[0]
.toString(),lon:docs[i].geometry.coordinates[1].toString()});
console.log(jsonText);
res.write(jsonText);
if(i!=intCount-1) res.write(",");
}
res.write("]");
}
res.end();
});});}).listen(1345, '0.0.0.0');
console.log('Server running at http00.0.0.1:1345:');
Agora vamos voltar a API do Google Maps para apresentar os valores armazenados no MongoDB. Em uma nova página vamos adicionar os mesmos scripts apresentados na Listagem 1. Na sequência, conforme comentado no código da Listagem 7, vamos criar um objeto Map, que é o valor mais básico para a API do Google Maps. Esse mapa tem como propriedades o tipo que será um ROADMAP (um mapa de estradas igual ao padrão do Google Maps), e vamos desligar a possibilidade de o usuário modificar o tipo de mapa, em mapTypeControl: false. Para adicionar as posições de cada passageiro no mapa vamos utilizar um objeto do tipo Marker provido pela API do Google Maps. Cada marker vai receber a latitude e longitude e apresentar o nome do passageiro.
<!DOCTYPE html>
<html>
<head>
<link href='http://fonts.googleapis.com/css?family=
Open+Sans:400,300,600,700,800' rel='stylesheet' type='text/css'>
<script src="http://maps.googleapis.com/maps/api/js?
key=<CHAVE>&sensor=false"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/
2.1.1/jquery.min.js"></script>
<script>
function apresentaLocalizacoes() {
$.get( "http://localhost:1345/", function( data ) {
var lat=-20.1;
var lon=50.1;
var myLatlng = new google.maps.LatLng(lat, lon);
var mapProp = {
center:myLatlng,
zoom:5,
mapTypeId:google.maps.MapTypeId.ROADMAP,
mapTypeControl: false
};
//criando objeto mapa
var map=new google.maps.Map(document
.getElementById("googleMap"),mapProp);
var obj = jQuery.parseJSON(data);
$.each($.parseJSON(data), function(idx, obj) {
var lat=obj.lat;
var lon=obj.lon;
var myLatlng = new google.maps.LatLng(lat, lon);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: obj.nome
});
});
});
}
</script>
</head>
<body onload='apresentaLocalizacoes()'>
<div id="googleMap" style="position:fixed;
top:0px;left:0px;width:100%;height:700px;">
</body>
</html>
A Figura 1 apresenta a localização dos passageiros em um mapa do Google maps.
Obviamente, essa aplicação não é suficiente para ajudar usuários que estejam buscando taxi. Assim, podemos criar também a interface para que taxistas informem a sua posição. Para tal, vamos criar uma nova collection chamada taxis, conforme ilustrado na Listagem 8.
db.createCollection("passageiros", { capped : true, size
: 5242880, max : 5000 } )
Na sequência vamos criar uma função em Node.js, de forma parecida aos códigos apresentados anteriormente. Na Listagem 9 vamos receber a posição na qual o taxi se encontra em determinado momento e registrar essa posição e o nome do taxista naquele momento. Vamos ocultar o código HTML, pois tem as mesmas características da Listagem 2.
var http = require('http');
var url = require('url');
http.createServer(function (req, res) {
var url_parts = url.parse(req.url, true);
var query = url_parts.query;
var latitude = query.lat;
var longitude = query.lon;
var taxista = query.taxista;
// Retrieve
var MongoClient = require('mongodb').MongoClient;
//Conexão ao MongoDB
MongoClient.connect("mongodb://localhost:27017/devmedia", function(err, db) {
if(err) { return console.dir(err); }
//Escolher a collection taxi
var collection = db.collection(taxis);
var doc = {
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [latitude, longitude]
},
'properties': {
'name': taxista
}
}
collection.insert(doc , { w: 0 });
});}).listen(1346, '0.0.0.0');
console.log('Server running at http 0.0.0.0:1346:');
Com a localização dos taxistas registrados no MongoDB podemos, baseado no posicionamento de um passageiro, recuperar quais são os taxistas mais próximos. Novamente vamos criar uma função node.js para realizar essa busca e retornar os valores esperados. O primeiro passo e conectar-se a colection taxis do banco de dados devmedia. Com isso, podemos enviar uma consulta que irá filtrar usando o operador $near. Esse operador irá receber a posição atual do passageiro e retornar os taxis mais próximos a ele em uma lista.
var http = require('http');
http.createServer(function (req, res) {
var url_parts = url.parse(req.url, true);
var query = url_parts.query;
var latitude = query.lat;
var longitude = query.lon;
// Retrieve
var MongoClient = require('mongodb').MongoClient;
// Connect to the db
MongoClient.connect("mongodb://localhost:27017/devmedia",
function(err, db) {
if(err) { return console.dir(err); }
var taxis = db.collection('taxis');
taxis.find({ loc: { $near: [latitude, longitude ] } })
.toArray(function(err, docs){
res.writeHead(200, {
'Content-Type': 'text/html',
'Access-Control-Allow-Origin' : '*'});
var intCount = docs.length;
console.log(intCount);
if(intCount > 0){
res.write("[");
for(var i=0; i<intCount;i++){
var jsonText = JSON.stringify({nome: docs[i]
.properties.name.toString(),lat:docs[i].geometry
.coordinates[0].toString(),lon:docs[i].geometry
.coordinates[1].toString()});
console.log(jsonText);
res.write(jsonText);
if(i!=intCount-1) res.write(",");
}
res.write("]");
}
res.end();
});});}).listen(1347, '0.0.0.0');
console.log('Server running at http00.0.0.1:1347:');
No Google Maps poderemos agora apresentar os resultados da Listagem 10diretamente no mapa. A função da Listagem 11 pode ser alterada a fim de diferenciar os marcadores de taxis em relação aos marcadores de passageiros.
<!DOCTYPE html>
<html>
<head>
<link href='http://fonts.googleapis.com/css?family=
Open+Sans:400,300,600,700,800'
rel='stylesheet' type='text/css'>
<script src="http://maps.googleapis.com/maps/api/
js?key=<CHAVE>&sensor=false"></script>
<script src="http://ajax.googleapis.com/ajax/libs/
jquery/2.1.1/jquery.min.js"></script>
<script>
function apresentaTaxis() {
$.get( "http://localhost:1347/", function( data ) {
var lat=-20.1;
var lon=50.1;
var myLatlng = new google.maps.LatLng(lat, lon);
var mapProp = {
center:myLatlng,
zoom:5,
mapTypeId:google.maps.MapTypeId.ROADMAP,
mapTypeControl: false
};
//criando objeto mapa
var map=new google.maps.Map(document
.getElementById("googleMap"),mapProp);
var obj = jQuery.parseJSON(data);
$.each($.parseJSON(data), function(idx, obj) {
var lat=obj.lat;
var lon=obj.lon;
var myLatlng = new google.maps.LatLng(lat, lon);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: obj.nome
});
});
});
}
</script>
</head>
<body onload='apresentaLocalizacoes()'>
<div id="googleMap" >
</body>
</html>
Esse exemplo pode ser expandido usando as capacidades do MongoDB para calcular a distância de pontos, verificar se um passageiro está na área de atuação de taxistas ou mesmo para criar uma aplicação Android para recuperar automaticamente os valores de latitude e longitude diretamente do GPS. Além disso, poderíamos utilizar o documento recuperado do MongoDB usando o a função map.data.loadGeoJson da API do Google Maps, que carrega os pontos diretamente do documento GeoJSON.
Artigos relacionados
-
Artigo
-
Artigo
-
Vídeo
-
Artigo
-
DevCast