Uma consulta geoespacial é uma busca no banco que filtra e ordena registros por localização — perto de um ponto, dentro de um raio ou dentro de uma área. É ela que move o pedido de feature que aparece no segundo mês de quase todo produto: encontrar X por perto — cafés, motoristas, lojas, outros usuários. E é o caso mais claro de uma classe de consulta que a indexação B-tree comum não consegue atender: proximidade é bidimensional, e uma estrutura ordenada em uma única dimensão não enxerga isso.
Principais pontos
| Pergunta | Resposta |
|---|---|
| O tipo de campo | GeoPoint — um par latitude/longitude que o banco entende |
| As consultas | Near (ordenada por distância), dentro do raio, dentro da caixa/polígono |
| O índice | Estilo 2dsphere: o globo mapeado em células indexáveis |
| Sem ele | Distância calculada até cada linha — um full scan com trigonometria |
| A feature canônica | ”Encontrar X por perto”, composta com filtros comuns |
A consulta de proximidade, escrita e sentida
// JavaScript / Node.js — Back4app JS SDK
// "Find cafes within 2 km, nearest first" — the canonical geo query
const here = new Parse.GeoPoint({ latitude: 40.7484, longitude: -73.9857 });
const query = new Parse.Query('Cafe');
query.withinKilometers('location', here, 2); // radius filter, nearest-first
query.equalTo('openNow', true); // geo + ordinary filters compose
query.limit(20);
const cafes = await query.find();
cafes.forEach((c) => {
const km = here.kilometersTo(c.get('location'));
console.log(`${c.get('name')} — ${km.toFixed(2)} km away`);
}); // Flutter / Dart — Back4app Flutter SDK
// "Find cafes within 2 km, nearest first" — the canonical geo query
final here = ParseGeoPoint(latitude: 40.7484, longitude: -73.9857);
final query = QueryBuilder<ParseObject>(ParseObject('Cafe'))
..whereWithinKilometers('location', here, 2) // radius filter, nearest-first
..whereEqualTo('openNow', true) // geo + ordinary filters compose
..setLimit(20);
final response = await query.query();
for (final result in response.results ?? []) {
final cafe = result as ParseObject;
final loc = cafe.get<ParseGeoPoint>('location');
print('${cafe.get<String>('name')} at '
'${loc?.latitude}, ${loc?.longitude}');
} // iOS / Swift — Back4app Swift SDK
// "Find cafes within 2 km, nearest first" — the canonical geo query
let here = try ParseGeoPoint(latitude: 40.7484, longitude: -73.9857)
let query = Cafe.query(
withinKilometers(key: "location", geoPoint: here, distance: 2),
"openNow" == true // geo + ordinary filters compose
).limit(20)
query.find { result in
if case .success(let cafes) = result {
for cafe in cafes {
print("\(cafe.name ?? "?") — \(String(describing: cafe.location))")
}
}
} // Android / Kotlin — Back4app Android SDK
// "Find cafes within 2 km, nearest first" — the canonical geo query
val here = ParseGeoPoint(40.7484, -73.9857)
val query = ParseQuery.getQuery<ParseObject>("Cafe")
query.whereWithinKilometers("location", here, 2.0) // radius, nearest-first
query.whereEqualTo("openNow", true) // geo + filters compose
query.limit = 20
query.findInBackground { cafes, e ->
if (e == null) cafes.forEach { cafe ->
val loc = cafe.getParseGeoPoint("location")
val km = loc?.distanceInKilometersTo(here)
println("${cafe.getString("name")} — ${"%.2f".format(km)} km away")
}
} A mesma física em SQL, via PostGIS — e o índice que a torna viável:
-- Um índice espacial sobre a coluna geography:
CREATE INDEX cafe_location_gix ON cafe USING GIST (location);
-- "Cafés a até 2 km, do mais próximo ao mais distante":
SELECT name, ST_Distance(location, ST_MakePoint(-73.9857, 40.7484)::geography) AS meters
FROM cafe
WHERE ST_DWithin(location, ST_MakePoint(-73.9857, 40.7484)::geography, 2000)
ORDER BY location <-> ST_MakePoint(-73.9857, 40.7484)::geography
LIMIT 20;
-- com o índice: toca só as células que cobrem o círculo de 2 km
-- sem ele: calcula uma distância para cada linha da tabela
Como o índice enxerga o globo
Um índice estilo 2dsphere torna a proximidade indexável ao mapear a superfície curva em células hierárquicas cuja ordenação preserva a adjacência — pontos próximos no globo caem em entradas próximas do índice. Uma consulta por raio passa a se comportar como qualquer lookup em índice: identifique as poucas células que cobrem o círculo, varra os candidatos, verifique as distâncias exatas nessa lista curta. A geometria esférica — em vez da matemática de plano — mantém os resultados corretos em escalas reais, na travessia do antimeridiano e em direção aos polos.
A regra de composição decorre da mecânica comum de consultas: restrições geo se combinam livremente com filtros de igualdade, range e ponteiro (openNow == true nas abas acima), e os filtros não-geo seletivos das consultas quentes podem merecer índices próprios.
A paginação merece nota à parte, porque resultados ordenados por distância quebram o hábito do offset. Pular a primeira página de uma consulta near obriga a engine a reclassificar tudo que foi pulado, e um ponto que se moveu entre as requisições pode embaralhar a ordem sob os pés do usuário. Os padrões mais robustos: ampliar o raio progressivamente no “carregar mais”, ou paginar por uma chave estável dentro de um raio fixo. Ordenar por proximidade é um ranking sobre dados vivos — trate as fronteiras de página como indicativas, não como linhas de um livro-razão.
Near vs. within vs. consultas em plano
Qual consulta geo você deveria usar?
| Formato da consulta | Responde | Ordenação | Uso típico |
|---|---|---|---|
| Near (proximidade) | O que está mais perto daqui? | Do mais próximo ao mais distante | Listas de “cafés por perto”, matching de motoristas |
| Dentro do raio | O que está a até r km daqui? | Nenhuma implícita | Elegibilidade de entrega, alertas |
| Dentro da caixa | O que está neste retângulo? | Nenhuma | Renderização do viewport do mapa |
| Dentro do polígono | O que está dentro desta forma? | Nenhuma | Bairros, zonas, geofences |
| Plano (2d) | O mesmo, num plano projetado | Varia | Mapas de jogo, plantas baixas — não a Terra |
A distinção near/within é lógica de produto, não preciosismo: near é um ranking (limite-o com um limit e um raio máximo, ou cidades densas devolvem milhares de linhas), within é um predicado (case-o com a geometria do viewport ou da cerca). A linha do plano é a nota de rodapé honesta — para coordenadas que não estão sobre uma esfera, índices esféricos são a ferramenta errada.
Casos de uso comuns
- “Encontrar X por perto”. Cafés, academias, caixas eletrônicos, pontos de recarga — a lista de proximidade canônica, com raio limitado e do mais próximo primeiro.
- Matching e despacho. Passageiros para motoristas, corridas para entregadores — consultas near sobre GeoPoints atualizados com frequência.
- Viewports de mapa. Consultas dentro da caixa alimentando os pins conforme o usuário arrasta o mapa — baratas, sem ordenação, do tamanho do viewport.
- Geofencing. Checagens dentro do polígono para zonas de entrega, áreas de atendimento e lógica disparada por localização.
- Features sociais locais. Pessoas por perto e eventos deste fim de semana, compostos com filtros de privacidade e relacionamentos por ponteiro.
Você deveria usar consultas geo ou pré-computar regiões? Matriz de decisão
| Consulte ao vivo com índice geo quando… | Pré-compute rótulos de região quando… |
|---|---|
| Raios e formas variam a cada requisição | As fronteiras são fixas (lojas, zonas, distritos) |
| Os pontos se movem com frequência (motoristas, usuários) | A pertinência muda raramente |
| A ordenação por proximidade importa | Você só filtra por igualdade de região |
| As formas são genuinamente espaciais | Uma coluna region simples responde tudo |
| Você tem um índice espacial disponível | Você está agrupando, não medindo |
A saída de emergência importa: quando toda consulta se reduz a “está na zona A?”, uma coluna de texto indexada comum vence a maquinaria espacial — mais barata, mais simples e coberta por B-trees comuns. A indexação espacial se paga exatamente quando a geometria é dinâmica: centros arbitrários, pontos em movimento, distâncias reais.
Limitações e trade-offs
- Índices geo são especialistas. Atendem apenas predicados espaciais; os seus outros filtros continuam precisando de índices próprios, e manter índice custa escrita — mesmo imposto, alíquota espacial.
- Consultas near sem limite são armadilhas. Ordenar por proximidade numa cidade densa sem raio máximo nem limit classifica metade da tabela. Sempre limite a busca.
- Pontos que se movem escrevem o tempo todo. Localização de motoristas ao vivo significa atualizações de GeoPoint em alta frequência, cada uma mantendo o índice — agrupe em lote ou aplique throttle onde o produto permitir.
- Um ponto por registro é o modelo base. Uma loja com cinco filiais são cinco registros; formas mais ricas que pontos (rotas, áreas de cobertura) empurram para bancos espaciais completos.
- A precisão tem piso. O erro esfera-vs-elipsoide é desprezível, mas o ruído do GPS é de metros num dia bom — desenhe a lógica do produto (zonas, limiares) para tolerá-lo.
Consultas geoespaciais no Back4app
O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. GeoPoint é um tipo de coluna nativo no armazenamento gerenciado com MongoDB, e os operadores de proximidade, raio e caixa — withinKilometers, near, withinGeoBox — vêm nas APIs geradas automaticamente e em todos os SDKs, exatamente como as abas de código acima os usam. Os índices geo são gerenciados junto com o resto da sua estratégia de índices no dashboard, o que transforma o habitual projeto de infraestrutura de “encontrar X por perto” numa decisão de schema e três linhas de query.
Perguntas frequentes
O que é uma consulta geoespacial?
Uma busca no banco cujo filtro é espacial, não por valor: retorne registros perto de um ponto, dentro de um raio ou dentro de uma caixa ou polígono, normalmente ordenados do mais próximo para o mais distante. O banco guarda coordenadas como um tipo de primeira classe — um GeoPoint de latitude e longitude — e um índice espacial responde à pergunta sem calcular a distância até cada linha.
O que é um campo GeoPoint?
Um tipo de coluna que guarda um par latitude/longitude, com latitude de -90 a 90 e longitude de -180 a 180. Como o banco sabe que o campo é geográfico — e não apenas dois floats —, ele consegue indexá-lo espacialmente e expor operadores de distância: dentro de X quilômetros ou milhas daqui, dentro desta bounding box, contido neste polígono, ordenado por proximidade.
Como funciona um índice geoespacial 2dsphere?
Ele mapeia a superfície curva da Terra em células ordenadas e indexáveis — células grosseiras subdivididas em outras mais finas —, de modo que proximidade no globo vira adjacência no índice. Uma consulta de proximidade inspeciona o punhado de células que cobrem a área de busca em vez de cada linha, e a geometria esférica mantém as distâncias honestas, inclusive na travessia do antimeridiano e perto dos polos.
Por que a busca por proximidade fica lenta sem índice geo?
Porque sem ele a engine precisa calcular a distância do seu ponto até cada linha e depois ordenar tudo — um full scan vestido de trigonometria, repetido a cada requisição. Um índice geo inverte o trabalho: vai direto às células que cobrem o raio de busca e toca apenas candidatos plausíveis. A diferença cresce com o tamanho da tabela, exatamente como em qualquer índice ausente, só que mais cara por linha.
Qual a diferença entre consulta near e consulta within?
Uma consulta near responde "o que está mais perto?" — ordena por distância a partir de um ponto e normalmente limita o resultado com um limit ou um raio máximo. Uma consulta within responde "o que está dentro?" — filtra por contenção num raio, caixa ou polígono, sem implicar ordenação. Listas de cafés próximos são near; "lojas neste viewport do mapa" e checagens de geofence são within.
Dá para combinar filtros geo com filtros comuns?
Dá, e features reais quase sempre combinam: dentro de 2 km *e* aberto agora *e* com nota acima de quatro estrelas. A restrição geo compõe com filtros de igualdade, range e ponteiro na mesma consulta. Fique atento à interação com a indexação — o índice espacial estreita primeiro pela localização, e filtros comuns muito seletivos podem merecer índice próprio para a consulta combinada continuar barata.
Qual a precisão das consultas por raio em distâncias grandes?
Cálculos esféricos modelam a Terra como uma esfera, o que difere do elipsoide real em até cerca de um terço de um por cento — metros em distâncias urbanas, e em geral irrelevante para a lógica do produto. O que morde antes é a precisão dos próprios pontos armazenados: coordenadas de GPS de celular carregam metros de erro ao ar livre, e mais dentro de prédios. Para "encontrar X por perto", os dois efeitos são ruído.