Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
C#chevron-right

Queries geoespaciais do MongoDB em C#

Adrienne Tacke11 min read • Published Feb 09, 2022 • Updated May 12, 2022
C#
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

Consultas geoespaciais do MongoDB com C#

Se você já deu uma olhada em um mapa para encontrar os locais de lanchonete mais próximos de você, provavelmente usou uma query geoespacial sob o capô! Utilizando objetosGeoJSONdo para armazenar dados geoespaciais no MongoDB Atlas, você pode criar suas próprias queries geoespaciais para seu aplicativo. Neste tutorial, veremos como trabalhar com queries geoespaciais no driver C# do MongoDB.

Salto rápido

O que são consultas geoespaciais?

As queries geoespaciais permitem a você trabalhar com dados geoespaciais. Seja em um espaço 2d (como um mapa plano) ou 3d (ao visualizar uma representação esférica do mundo), os dados geoespaciais permitem que você encontre áreas e lugares em referência a um ponto ou conjunto de pontos.
Isso pode parecer complicado, mas você provavelmente já encontrou esses casos de uso no dia a dia: procurar pontos de interesse em uma nova cidade que você esteja explorando, descobrir quais cafés são mais próximos de você ou encontrar todas as confeiteiros em um raio de três quilômetros raio da sua posição atual (para a ciência!).
Esses tipos de queries podem ser feitas facilmente com operadores especiais de query geoespacial no MongoDB. E, para nossa sorte, esses operadores também são implementados na maioria dos drivers do MongoDB, incluindo o driver C# que usaremos neste tutorial.

GeoJSON

Um aspecto importante do trabalho com dados geoespaciais é algo chamado formatoGeoJSON. É um padrão aberto para representar características geográficas simples e facilita o trabalho com dados geoespaciais. Veja como são alguns dos tipos de objetos GeoJSON:
1// Point GeoJSON type
2{
3 "type" : "Point",
4 "coordinates" : [-115.20146200000001, 36.114704000000003]
5}
6
7// Polygon GeoJSON type
8{
9 "type": "Polygon",
10 "coordinates": [
11 [
12 [100.0, 0.0],
13 [101.0, 0.0],
14 [101.0, 1.0],
15 [100.0, 1.0],
16 [100.0, 0.0]
17 ]
18 ]
19}
Enquanto o MongoDB suporta armazenar seus dados geoespaciais como legacy coordinate pairs, é preferível trabalhar com o formato GeoJSON , pois ele torna as queries complicadas possíveis e muito mais simples.
💡 Seja trabalhando com coordenadas no formato GeoJSON ou como legacy coordinate pairs, as consultas exigem que a longitude seja passada primeiro, seguida pela latitude. Isso pode parecer "retrógrado" em comparação com o que você pode estar acostumado, mas tenha certeza de que esse formato realmente segue a ordem(X, Y)da matemática! Lembre-se disso, pois as consultas geoespaciais do MongoDB também exigirão que as coordenadas sejam passadas em [longitude, latitude] formato, quando aplicável.
Tudo bem, vamos começar com o tutorial!

Pré-requisitos

Atlas Setup

Para facilitar o acompanhamento deste tutorial, trabalharemos com os conjuntos de dadosrestaurants e neighborhoods, ambos disponíveis publicamente em nossa documentação. Ambos são arquivosJSON que contêm uma quantidade significativa de dados de restaurantes e bairros de Nova York já no formato GeoJSON!

Faça o download dos dados de amostra e importe para o seu cluster do Atlas

Esses arquivos são diferentes do conjunto de dadossample_restaurantsque pode ser carregado no Atlas! Embora os nomes das coleções sejam os mesmos, os arquivos JSON que estou pedindo para você baixar já têm dados no formato GeoJSON, que serão necessários para este tutorial.
Em seguida, siga estas instruções para importar os dois conjuntos de dados para o cluster.
} Quando você chegar à Etapa 5 de importação de dados para o cluster (Executar mongoimport), certifique-se de acompanhar os nomesdatabase e collection que você passa para o comando. Vamos precisar deles mais tarde! Se você quiser usar os mesmos nomes que neste tutorial, meu banco de dados se chama sample-geo, e minhas collections se chamam restaurants e neighborhoods .

Criar índices 2dsphere

Por último, para trabalhar com dados geoespaciais, um índice2dsphere precisa ser criado para cada collection. Você pode fazer isso no portal do MongoDB Atlas.
Primeiro, navegue até seu cluster e clique em "Browse Collections":
Captura de tela da UI do MongoDB Atlas com um perfil verde destacando o botão "Browse Collections".
Você será direcionado para a sua lista de coleções. Encontre os dados do seu restaurante (se estiver acompanhando, será uma coleção chamada restaurants dentro do banco de dadossample-geo).
Com a coleção selecionada, clique na aba "Índices":
Captura de tela da UI do MongoDB Atlas com Contorno verde destacando a aba "Índices".
Clique no botão "CREATE INDEX" para abrir o assistente de criação de índice. Na seção "Campos", você especificará em qual campo criar um índice, bem como em qual tipo de índice. Para nosso tutorial, limpe a entrada, copie e cole o seguinte:
1{ "location": "2dsphere" }
Clique em "Revisar". Você será solicitado a confirmar a criação de um índice em sample-geo.restaurants no campo { "location": "2dsphere" } (lembre-se, se você não estiver usando os mesmos nomes de banco de dados e coleção, confirme se o índice está sendo criado em yourDatabaseName.yourCollectionName). Clique em "Confirmar".
Da mesma forma, encontre os dados da sua vizinhança (sample-geo.neighborhoods, a menos que você tenha usado nomes diferentes). Selecione sua coleçãoneighborhoods e faça a mesma coisa, desta vez criando este índice:
1{ "geometry": "2dsphere" }
Quase instantaneamente, os índices serão criados. Você saberá que o índice foi criado com êxito depois de vê-lo listado na guia Índices da coleção selecionada.
Captura de tela da localização_2dsphere criado no MongoDB Atlas.
Agora, você está pronto para trabalhar com os dados do seu restaurante e bairro!

Criando o projeto

Para mostrar essas amostras, trabalharemos dentro do contexto de um programa de console simples. Implementaremos cada operador de query geoespacial como seu próprio método e registraremos a query MongoDB correspondente que ele executa.
Após criar um novo projeto de console, adicione o driver MongoDB ao seu projeto usando o Gerenciador de pacotes ou o .NET CLI:
Gerente de pacotes
1Install-Package MongoDB.Driver
.NET CLI
1dotnet add package MongoDB.Driver
Em seguida, adicione as seguintes dependências ao seu Program.cs arquivo :
1using MongoDB.Bson;
2using MongoDB.Bson.IO;
3using MongoDB.Bson.Serialization;
4using MongoDB.Driver;
5using MongoDB.Driver.GeoJsonObjectModel;
6using System;
Para todos os nossos exemplos, usaremos as seguintes classesRestaurant e Neighborhood como nossos modelos:
1public class Restaurant
2{
3 public ObjectId Id { get; set; }
4 public GeoJsonPoint<GeoJson2DCoordinates> Location { get; set; }
5 public string Name { get; set; }
6}
1public class Neighborhood
2{
3 public ObjectId Id { get; set; }
4 public GeoJsonPoint<GeoJson2DCoordinates> Geometry { get; set; }
5 public string Name { get; set; }
6}
Adicione ambos ao seu aplicativo. Para simplificar, adicionei-os como classes adicionais no meu arquivoProgram.cs.
Em seguida, precisamos nos conectar ao nosso cluster. Coloque o seguinte código dentro do métodoMain do seu programa:
1// Be sure to update yourUsername, yourPassword, yourClusterName, and yourProjectId to your own!
2// Similarly, also update "sample-geo", "restaurants", and "neighborhoods" to whatever you've named your database and collections.
3var client = new MongoClient("mongodb+srv://yourUsername:yourPassword@yourClusterName.yourProjectId.mongodb.net/sample-geo?retryWrites=true&w=majority");
4var database = client.GetDatabase("sample-geo");
5var restaurantCollection = database.GetCollection<Restaurant>("restaurants");
6var neighborhoodCollection = database.GetCollection<Neighborhood>("neighborhoods");
Finalmente, adicionaremos um método auxiliar chamado Log() dentro de nossa classeProgram. Isto pegará as queries geoespaciais que escrevemos em C# e registrará a Query MongoDB correspondente no console. Isso nos dá uma maneira fácil de copiá-lo e usá-lo em outro lugar.
1private static void Log(string exampleName, FilterDefinition<Restaurant> filter)
2{
3 var serializerRegistry = BsonSerializer.SerializerRegistry;
4 var documentSerializer = serializerRegistry.GetSerializer<Restaurant>();
5 var rendered = filter.Render(documentSerializer, serializerRegistry);
6 Console.WriteLine($"{exampleName} example:");
7 Console.WriteLine(rendered.ToJson(new JsonWriterSettings { Indent = true }));
8 Console.WriteLine();
9}
Agora temos nossa estrutura montada. Agora podemos criar os métodos de consulta geoespacial!

Exemplos de código de query geoespacial em C#

Como o MongoDB tem operadores dedicados para queries geoespaciais, podemos aproveitar o construtor de definição de filtrodo driver C# para construir queries seguras contra erros de digitação. O uso do construtor de definições de filtro também oferece segurança em tempo de compilação e suporte à refatoração no Visual Studio, o que o torna uma ótima maneira de trabalhar com queries geoespaciais.

Exemplo de $near em C#

O filtro .Nearimplementa o operador de query geoespacial$near . Utilize isto quando você deseja retornar objetos geoespaciais que estão próximos a um ponto central, com resultados classificados do mais próximo para o mais distante.
Em nosso programa, vamos criar um método NearExample()que faça isso. Vamos procurar restaurantes que estejam ano máximo 10,000 metros de distância e a pelo menos 2,000 metros de distância de uma Magnolia Bakery (na Bleecker Street) em Nova York:
1private static void NearExample(IMongoCollection<Restaurant> collection)
2{
3 // Instantiate builder
4 var builder = Builders<Restaurant>.Filter;
5
6 // Set center point to Magnolia Bakery on Bleecker Street
7 var point = GeoJson.Point(GeoJson.Position(-74.005, 40.7358879));
8
9 // Create geospatial query that searches for restaurants at most 10,000 meters away,
10 // and at least 2,000 meters away from Magnolia Bakery (AKA, our center point)
11 var filter = builder.Near(x => x.Location, point, maxDistance: 10000, minDistance: 2000);
12
13 // Log filter we've built to the console using our helper method
14 Log("$near", filter);
15}
É isso ai! Sempre que chamamos esse método, uma query$near será gerada que você pode copiar e colar do console. Sinta-se livre para colar essa query no explorador de dados no Atlas para ver quais restaurantes correspondem ao filtro (não se lembre de alterar "Location"para um"location"em letra minúscula ao trabalhar no Atlas). Em uma publicação futura, abordaremos como visualizar esses resultados em um mapa!
Por enquanto, você pode chamar esse método (e todos os outros métodos a seguir) a partir do métodoMainda seguinte forma:
1static void Main(string[] args)
2{
3 var client = new MongoClient("mongodb+srv://yourUsername:yourPassword@yourClusterName.yourProjectId.mongodb.net/sample-geo?retryWrites=true&w=majority");
4 var database = client.GetDatabase("sample-geo");
5 var restaurantCollection = database.GetCollection<Restaurant>("restaurants");
6 var neighborhoodCollection = database.GetCollection<Neighborhood>("neighborhoods");
7
8 NearExample(restaurantCollection);
9 // Add other methods here as you create them
10}
Sinta-se à vontade para modificar este código! Altere o ponto central mudando as coordenadas ou deixe que o método aceite variáveis para os parâmetrospoint, maxDistance e minDistance em vez de codificá-los.
Na maioria dos casos de uso, .Near resolverá o problema. Ele mede distâncias contra um plano plano 2d (plano euclidiano) que será preciso para a maioria das aplicações. No entanto, se você precisar que as consultas sejam executadas em geometria esférica 3d ao medir distâncias, use o filtro.NearSphere (que implementa o operador$nearSphere ). Ele aceita os mesmos parâmetros que.Near, mas calculará distâncias usando geometria esférica.

$geoWithin Exemplo em C#

O filtro .GeoWithinimplementa o operador de query geoespacial$geoWithin . Utilize isto quando você deseja retornar objetos geoespaciais que existem inteiramente dentro de uma forma especificada, seja um legacy coordinate pairs Polygon, MultiPolygonou forma definida por GeoJSON. Como você verá em um exemplo posterior, esta forma pode ser um círculo e pode ser gerada utilizando o operador$center .
Para implementar isso em nosso programa, vamos criar um métodoGeoWithinExample() que procure restaurantes em uma área, especificamente nesta área:
Visualização do mapa da cidade de Nova York mostrando uma área sombreada.
No código, descrevemos esta área como um polígono e usamos ele como uma lista de pontos:
1private static void GeoWithinExample(IMongoCollection<Restaurant> collection)
2{
3 var builder = Builders<Restaurant>.Filter;
4
5 // Build polygon area to search within.
6 // This must always begin and end with the same coordinate
7 // to "close" the polygon and fully surround the area.
8 var coordinates = new GeoJson2DCoordinates[]
9 {
10 GeoJson.Position(-74.0011869, 40.752482),
11 GeoJson.Position(-74.007384, 40.743641),
12 GeoJson.Position(-74.001856, 40.725631),
13 GeoJson.Position(-73.978511, 40.726793),
14 GeoJson.Position(-73.974408, 40.755243),
15 GeoJson.Position(-73.981669, 40.766716),
16 GeoJson.Position(-73.998423, 40.763535),
17 GeoJson.Position(-74.0011869, 40.752482),
18 };
19 var polygon = GeoJson.Polygon(coordinates);
20
21 // Create geospatial query that searches for restaurants that fully fall within the polygon.
22 var filter = builder.GeoWithin(x => x.Location, polygon);
23
24 // Log the filter we've built to the console using our helper method.
25 Log("$geoWithin", filter);
26}

Exemplo de $geoIntersects em C#

O filtro .GeoIntersectsimplementa o operador de query geoespacial$geoIntersects . Utilize isto quando você deseja retornar objetos geoespaciais que abrangem a mesma área que um objeto especificado, geralmente um ponto.
Para o nosso programa, vamos criar um métodoGeoIntersectsExample()que verifica se um ponto especificado está dentro de um dos bairros armazenados em nossa coleção de bairros:
1private static void GeoIntersectsExample(IMongoCollection<Neighborhood> collection)
2{
3 var builder = Builders<Neighborhood>.Filter;
4
5 // Set specified point. For example, the location of a user (with granted permission)
6 var point = GeoJson.Point(GeoJson.Position(-73.996284, 40.720083));
7
8 // Create geospatial query that searches for neighborhoods that intersect with specified point.
9 // In other words, return results where the intersection of a neighborhood and the specified point is non-empty.
10 var filter = builder.GeoIntersects(x => x.Geometry, point);
11
12 // Log the filter we've built to the console using our helper method.
13 Log("$geoIntersects", filter);
14}
💡 Para este método, um métodoLog()sobrecarregado que aceite um FilterDefinition do tipo Neighborhood precisa ser criado.

Exemplo combinado de $geoWithin e $center em C#

Como vimos, o $geoWithin operador retorna objetos geoespaciais que existem inteiramente dentro de uma forma especificada. Podemos definir essa forma como um círculo usando o $center operador .
Vamos criar um métodoGeoWithinCenterExample() em nosso programa. Este método procurará todos os restaurantes existentes dentro de um círculo que centralizamos na ponte do Brooklyn:
1private static void GeoWithinCenterExample(IMongoCollection<Restaurant> collection)
2{
3 var builder = Builders<Restaurant>.Filter;
4
5 // Set center point to Brooklyn Bridge
6 var point = GeoJson.Point(GeoJson.Position(-73.99631, 40.705396));
7
8 // Create geospatial query that searches for restaurants that fall within a radius of 20 (units used by the coordinate system)
9 var filter = builder.GeoWithinCenter(x => x.Location, point.Coordinates.X, point.Coordinates.Y, 20);
10 Log("$geoWithin.$center", filter);
11}

Exemplo combinado de $geoWithin e $centerSphere em C#

Outra maneira de fazer query de locais é combinando os operadores de query geoespacial$geoWithin e $centerSphere . Ele difere do operador$center de algumas maneiras:
  • $centerSphere usa a geometria esférica, enquanto $center usa a geometria plana para os cálculos.
  • $centerSphere funciona com objetos GeoJSON e legacy coordinate pairs, enquanto $center funciona e retorna legacy coordinate pairs.
  • $centerSphere usa radianos para distância, o que requer cálculos adicionais para produzir uma consulta precisa. $center usa as unidades usadas pelo sistema de coordenadas e pode ser menos preciso para algumas consultas.
Veremos nosso método de exemplo em um momento, mas primeiro, um pequeno contexto de como calcular radianos para geometria esférica!

Cálculos de geometria esférica com radianos

💡 Uma coisa importante sobre trabalhar com $centerSphere (e quaisquer outros operadores geoespaciais que usam geometria esférica) é que ele usa radianos para distância. Isso significa que as unidades de distância usadas nas consultas (milhas ou quilômetros) primeiro precisam ser convertidas em radianos. O uso de radianos considera corretamente a natureza esférica do objeto que estamos medindo (geralmente a Terra) e permite que o operador$centerSphere calcule as distâncias corretamente.
Use esta tabela útil para converter entre distâncias e radianos:
ConversãoDescriçãoExemplo de cálculo
Distância (milhas) para radianosDivida a distância pelo raio da esfera (por exemplo, a Terra) em milhas. O raio equitorial da Terra em milhas é aproximadamente 3,963.2.Pesquisar objetos com um raio de 100 milhas: 100 / 3963.2
Distância (quilômetros) para radianosDivida a distância pelo raio da esfera (por exemplo, a Terra) em quilômetros. O raio equatorial da Terra em quilômetros é de aproximadamente 6,378.1.Pesquise objetos com raio de 100 quilômetros: 100 / 6378.1
radianos para distância (milhas)Multiplique a medida em radianos pelo raio da esfera (por exemplo, a Terra). O raio equitorial da Terra em milhas é aproximadamente 3,963.2.Encontre a medida em radianos de 50 em milhas: 50 * 3963.2
radianos para distância (quilômetros)Multiplique a medida do radiano pelo raio da esfera (por exemplo, a Terra). O raio equitorial da Terra em quilômetros é de aproximadamente 6,378.1.Encontre a medida em radianos de 50 em quilômetros: 50 * 6378.1

Vamos voltar ao exemplo!

Para o nosso programa, vamos criar um GeoWithinCenterSphereExample() que busca todos os restaurantes em um raio de três milhas do Apollo Theater no Harlem:
1private static void GeoWithinCenterSphereExample(IMongoCollection<Restaurant> collection)
2{
3 var builder = Builders<Restaurant>.Filter;
4
5 // Set center point to Apollo Theater in Harlem
6 var point = GeoJson.Point(GeoJson.Position(-73.949995, 40.81009));
7
8 // Create geospatial query that searches for restaurants that fall within a 3-mile radius of Apollo Theater.
9 // Notice how we pass our 3-mile radius parameter as radians (3 / 3963.2). This ensures accurate calculations with the $centerSphere operator.
10 var filter = builder.GeoWithinCenterSphere(x => x.Location, point.Coordinates.X, point.Coordinates.Y, 3 / 3963.2);
11
12 // Log the filter we've built to the console using our helper method.
13 Log("$geoWithin.$centerSphere", filter);
14}

Próxima vez em consultas geoespaciais em C#

Como vimos, trabalhar com queries geoespaciais do MongoDB em C# é possível por meio de seu suporte para os operadores de consulta geoespacial. Em outro tutorial, veremos como visualizar nossos resultados de consulta geoespacial em um mapa!
Se você tiver alguma dúvida ou estiver preso, não hesite em publicar em nossos MongoDB Community! E se você encontrou este tutorial útil, não se lembre de avaliá-lo e deixar qualquer feedback. Isso nos ajuda a melhorar nossos artigos para que eles sejam incríveis para todos!

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Trabalhando com transações MongoDB com C# e .NET Framework


Sep 11, 2024 | 3 min read
Artigo

Como configurar mapas de classes do MongoDB para C# para otimizar o desempenho de query e o tamanho de armazenamento


Aug 05, 2024 | 8 min read
Tutorial

Salvando dados no Unity3D usando o PlayPrefs


Sep 09, 2024 | 11 min read
Tutorial

Interaja com o MongoDB Atlas em uma função do AWS Lambda usando C#


Jan 23, 2024 | 5 min read
Sumário
  • Consultas geoespaciais do MongoDB com C#