---
term: 'Consultas Geoespaciais & Indexação por Localização'
seoTitle: 'Consultas Geoespaciais e Indexação por Localização em BaaS'
headline: 'O que são Consultas Geoespaciais?'
slug: consultas-geoespaciais
category: database
shortDefinition: '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.'
relatedTerms:
  - database-index
  - database-queries
  - relational-queries-document-databases
  - auto-generated-database-apis
contrastsWith:
  - database-index
faq:
  - question: 'O que é uma consulta geoespacial?'
    answer: '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.'
  - question: 'O que é um campo GeoPoint?'
    answer: '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.'
  - question: 'Como funciona um índice geoespacial 2dsphere?'
    answer: '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.'
  - question: 'Por que a busca por proximidade fica lenta sem índice geo?'
    answer: '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.'
  - question: 'Qual a diferença entre consulta near e consulta within?'
    answer: '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.'
  - question: 'Dá para combinar filtros geo com filtros comuns?'
    answer: '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.'
  - question: 'Qual a precisão das consultas por raio em distâncias grandes?'
    answer: '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.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'MongoDB geospatial queries'
    url: 'https://www.mongodb.com/docs/manual/geospatial-queries/'
  - name: 'Parse SDK guide — GeoPoints'
    url: 'https://docs.parseplatform.org/js/guide/'
  - name: 'PostGIS — spatial extension for PostgreSQL'
    url: 'https://postgis.net/'
  - name: 'Spatial database (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Spatial_database'
cta:
  title: 'Entregue o "perto de mim" ainda hoje'
  text: 'O Back4app dá a cada classe campos GeoPoint com consultas por raio, por caixa e por proximidade embutidas nas APIs geradas automaticamente e em todos os SDKs — a feature de localização que costuma exigir um desvio por banco espacial vira três linhas de query.'
  linkText: 'Comece grátis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-08-25'
translationKey: geospatial-queries-indexing
---

**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](/glossary/pt/indice-de-banco-de-dados/) 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:**

```javascript
// 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
// 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}');
}
```

**Swift:**

```swift
// 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))")
    }
  }
}
```

**Kotlin:**

```kotlin
// 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](https://postgis.net/) — e o índice que a torna viável:

```sql
-- 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

```mermaid
flowchart TB
  accTitle: Como um índice geo esférico responde a uma consulta por raio
  accDescr: A superfície da Terra é dividida em células hierárquicas guardadas em ordem. Uma consulta por raio seleciona as poucas células que cobrem o círculo de busca, varre apenas os pontos candidatos dentro delas e calcula distâncias exatas para essa lista curta.
  G["Globo dividido em<br/>células hierárquicas"] --> C1["Célula grosseira<br/>(escala de cidade)"]
  C1 --> F1["Células finas cobrindo<br/>o círculo de 2 km"]
  F1 --> P["Pontos candidatos<br/>só nessas células"]
  P --> D["Checagem de distância exata<br/>+ ordenação por proximidade"]
```

Um [índice estilo 2dsphere](https://www.mongodb.com/docs/manual/geospatial-queries/) 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](/glossary/pt/consultas-de-banco-de-dados/): 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](/glossary/pt/joins-em-bancos-de-documentos/).

## 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](https://en.wikipedia.org/wiki/Spatial_database) 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](/glossary/pt/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](/glossary/pt/indice-de-banco-de-dados/) 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.
