Как сохранить и запросить массив координат в строго типизированном драйвере C# Mongodb

Я использую официальный строго типизированный драйвер C# MongoDb версии 2.5.0 для взаимодействия с MongoDB.

У меня есть массив координат долготы и широты, и я хочу сохранить их в MongoDB.

Как называется класс, в котором хранится массив координат? Итак, в последнее время я могу выполнить следующий запрос: проверьте, находится ли данная координата рядом с любой точкой в ​​массиве координат, как этого добиться?

Вот простой код, демонстрирующий вопрос.

        var coordinates = new List<(double latitude, double longitude)>();

        //Store coordinates array in the database

        (double latitude, double longitude) point = (-33.847927, 150.6517805);

        int maxDistance = 300;//Max Distance in meters

        //Check if any point in the coordinates array is 300 m near the given point

Редактировать:-

Согласно этому вопросу, упомянутому в комментарии @CodeFuller ниже: -

Геопространственный индекс MongoDB в массиве (многоклавишный + геопространственный)

MongoDB не поддерживает геопространственный индекс для массивов, поэтому рассмотрите следующие классы:

class SomeDocument {

    public ObjectId Id { get; set; }

    public string Title { get; set; }

    public List<MyClass> Locations {get; set;} = new List<MyClass>();
}

class MyClass {

    public ObjectId Id { get; set; }

    public GeoJsonPoint<GeoJson2DGeographicCoordinates> Location { get; set; 

}

Как получить все экземпляры SomeDocument, у которых есть хотя бы одна точка рядом с данной точкой? И отсортировать их по ближайшему?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
2 668
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Драйвер MongoDB .NET предоставляет класс MongoDB.Driver.GeoJsonObjectModel.GeoJson2DGeographicCoordinates для двумерных географических координат.

Вот базовое использование:

  1. В классе модели определите свойство с типом GeoJsonPoint<GeoJson2DGeographicCoordinates>:

    public class SomeDocument
    {
        public ObjectId Id { get; set; }
    
        public string Title { get; set; }
    
        public GeoJsonPoint<GeoJson2DGeographicCoordinates> Location { get; set; }
    }
    
  2. Убедитесь, что у вас есть 2dsphere (или 2d, в зависимости от ваших потребностей) индекс для поля Location. Вы можете создавать и индексировать через клиент mongo:

    db.testCollection.createIndex( { Location : "2dsphere" } );

    Или через драйвер MongoDB .NET:

    var database = mongoClient.GetDatabase("testDB");
    IMongoCollection<SomeDocument> collection = database.GetCollection<SomeDocument>("testCollection");
    collection.Indexes.CreateOne(new IndexKeysDefinitionBuilder<SomeDocument>().Geo2DSphere(x => x.Location));
    
  3. Вставка данных:

    collection.InsertOne(new SomeDocument
    {
        Title = "Place #1",
        Location = GeoJson.Point(new GeoJson2DGeographicCoordinates(145.89, -35.83)),
    });
    
    collection.InsertOne(new SomeDocument
    {
        Title = "Place #2",
        Location = GeoJson.Point(new GeoJson2DGeographicCoordinates(154.98, -53.38)),
    });
    

    Обратите внимание, что в MongoDB вы сначала укажите долготу.

  4. Поиск соседей:

    var point = GeoJson.Point(new GeoJson2DGeographicCoordinates(145.889, -35.831));
    int maxDistance = 300;
    
    IAsyncCursor<SomeDocument> cursor = collection.FindSync(new FilterDefinitionBuilder<SomeDocument>().Near(x => x.Location, point, maxDistance: maxDistance));
    //  Check whether at least one is near the point
    var hasNeighbors = cursor.Any();
    

Пример проекта на GitHub

Спасибо за ответ, проблема в том, что поле местоположения представляет собой массив местоположений или, другими словами, маршрут или строку, как с этим выполнить ближайший запрос?

Waxren 12.04.2018 05:31

MongoDB не поддерживает геопространственные индексы для массивов. Индекс может быть создан для свойства, которое в основном составляет одну точку. Подробности см. В этот вопрос. Если вы хотите использовать MongoDB для поиска ближайших точек, ваш единственный вариант на данный момент - создать отдельный документ MongoDB для каждой точки маршрута и использовать оператор $near, как в ответе выше.

CodeFuller 12.04.2018 07:04

Спасибо за ответ

Waxren 12.04.2018 07:46

Хорошо. Что, если местоположение является свойством массива вложенного документа, могу ли я выполнить ближайший запрос. см. мое редактирование для дальнейшего объяснения

Waxren 13.04.2018 15:30

Обновления ответа @ CodeFuller.

Пункт 2.

CreateOne( new IndexKeysDefinitionBuilder..) амортизирован. Вместо этого используйте CreateOne( new CreateIndexModel()....

Вот как:

collection.Indexes.CreateOne(
                new CreateIndexModel<TDocument>(
                    new IndexKeysDefinitionBuilder<TDocument>().Geo2DSphere(x => x.Location)));

Позже я создал универсальную функцию для создания индексов при запуске следующим образом:

public CreateIndexes CreateGeoSpatialIndex<TDocument>(Expression<Func<TDocument, object>> field, string collectionName)
    {
        var collection = _database.GetCollection<TDocument>(collectionName);

        try
        {
            collection.Indexes.CreateOne(
                new CreateIndexModel<TDocument>(
                    new IndexKeysDefinitionBuilder<TDocument>().Geo2DSphere(field)));
        }
        catch (Exception ex) when (ex.Message.Contains("already exists"))
        {
            // Log info
        }

        return this;
    }

Пункт 4.

Кроме того, Near () у меня не работал, вместо этого мне пришлось использовать NearSphere () при запросе.

var filterDefinition = new FilterDefinitionBuilder<T>().NearSphere(x => x.Location, lng, lat, maxdistance)

Другие вопросы по теме