Как использовать геопространственный запрос в 2.1 MongoDB С# драйвер?

Я бил головой об этом один в течение нескольких дней. У меня очень простой запрос, который я пытаюсь запустить на С#, он выглядит так в оболочке.

db.runCommand({geoNear: "items", near: {type: "Point", coordinates : [-111.283344899999, 47.4941836]}, spherical : true, distanceMultiplier: 3963.2, maxDistance : 25});

Моя коллекция выглядит как

{    
  "_id" : ObjectId(),    
  "Title" : "arst",    
  "Description" : "<p>arst</p>",    
  "Date" : new Date("11/29/2015 09:28:15"),    
  "Location" : {    
    "type" : "Point",    
    "Coordinates" : [-111.28334489999998, 47.4941836]    
  },    
  "Zip" : "59405"    
}

В соответствии с документами MongoDB С# API Docs объект MongoDB.Driver.Builders.Query теперь устарел. Поэтому, когда я делаю что-то вроде этого

 var point = new GeoJson2DGeographicCoordinates(double.Parse(longitude), double.Parse(latitude)) ;
        var query = Query<Item>.Near(x => x.Location, new GeoJsonPoint<GeoJson2DGeographicCoordinates>(point), distance, true);

        var result = collection.Find(query);

Компилятор жалуется, что он не может конвертировать из IMongoQuery в FilterDefinition. Это говорит мне, что унаследованный Query < > builder не поддерживается новой библиотекой 2.1. Но для жизни меня я не могу найти нигде в api docs, ссылающихся на замену?

Может ли кто-нибудь указать мне в правильном направлении на выполнение этого простого геопространственного запроса в драйвере 2.1 С#? Я в тупике.

Кроме того, у меня есть индекс 2dsphere, созданный в коллекции, если бы я не выполнял команду оболочки. Здесь вывод индекса.

{
            "v" : 1,
            "key" : {
                    "Location.Coordinates" : "2dsphere"
            },
            "name" : "Location.Coordinates_2dsphere",
            "ns" : "ppn.items",
            "2dsphereIndexVersion" : 2
    }

ИЗМЕНИТЬ

После того, как я раскопал TON документации, я нашел его. Все примеры по-прежнему показывают унаследованный метод Query < > , но кажется, что новый метод является частью пространства имен Builders < > . Filter. Так что этот блок кода работает для меня,

 double lng = double.Parse(longitude);
 double lat = double.Parse(latitude);
 point = new GeoJson2DGeographicCoordinates(lng, lat);
 pnt = new GeoJsonPoint<GeoJson2DGeographicCoordinates>(point);
 dis = distance * 1609.34;
 fil = Builders<Item>.Filter.NearSphere(p => p.Location.Coordinates, pnt, dis);

 filter = filter & fil;

 var sort = Builders<Item>.Sort.Descending("Date");

 // This is the actual query execution
 List<Item> items = collection.Find(filter).Sort(sort).ToListAsync().Result;

Этот кодовый блок очень грязный, это результат попытки и сбой снова и снова. Я уверен, что я выясню способы его очистки. Мне кажется немного подробным, что вам нужно создать GeoJsonPoint из GeoJson2DGeographicCoordinates, но я уверен, что для этого есть веская причина. Если кто знает, пожалуйста, не стесняйтесь комментировать. Любые предложения по улучшению этого ответа очень приветствуются, это разочаровывает процесс документирования, поэтому, надеюсь, это поможет указать кому-то в правильном направлении.

Ответ 1

вот как я делаю это с моей стороны:

    public IQueryable<TEntity> FindNear<TEntity>(string collectionName, Expression<Func<TEntity, object>> field, double longitude, double latitude, double maxDistanceInKm) where TEntity : IEntity
    {
        var collection = database.GetCollection<TEntity>(collectionName);
        var point = GeoJson.Point(GeoJson.Geographic(longitude, latitude));
        var filter = Builders<TEntity>.Filter.Near(field, point, maxDistanceInKm * 1000);
        return collection.Find(filter).ToList().AsQueryable();
    }

Ответ 2

Вот наиболее удобный способ выполнить запросы геопространственной агрегации для всех, кто интересуется:

using MongoDB.Driver;
using MongoDB.Entities;
using System;

namespace StackOverflow
{
    public class Program
    {
        public class Place : Entity
        {
            public string Name { get; set; }
            public DateTime Date { get; set; }
            public Coordinates2D Location { get; set; }
            public double DistanceMeters { get; set; }
        }

        static void Main(string[] args)
        {
            //connect to mongodb
            new DB("test");

            //create a geo2dsphere index
            DB.Index<Place>()
              .Key(x => x.Location, KeyType.Geo2DSphere)
              .Option(x => x.Background = false)
              .Create();

            //create and save a place
            var paris = new Place
            {
                Name = "paris",
                Location = new Coordinates2D(48.8539241, 2.2913515),
                Date = DateTime.UtcNow
            };
            paris.Save();

            var eiffelTower = new Coordinates2D(48.857908, 2.295243);

            //find all places within 1km of eiffel tower.
            var places = DB.GeoNear<Place>(
                              NearCoordinates: eiffelTower,
                              DistanceField: x => x.DistanceMeters,
                              MaxDistance: 1000)
                           .SortByDescending(x=>x.Date)
                           .ToList();
        }
    }
}

он генерирует следующий конвейер агрегации:

{
                "$geoNear": {
                    "near": {
                        "type": "Point",
                        "coordinates": [
                            48.857908,
                            2.295243
                        ]
                    },
                    "distanceField": "DistanceMeters",
                    "spherical": true,
                    "maxDistance": NumberInt("1000")
                }
            },
            {
                "$sort": {
                    "Date": NumberInt("-1")
                }
            }

все вышеперечисленное сделано с использованием удобной библиотеки MongoDB.Entities, автором которой я являюсь.