Геопространственный индекс MongoDB в C#

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

Код:

MongoUrl url = new MongoUrl("mongodb://xxx.xx.x.xx/mydb");
MongoServer server = MongoServer.Create(url);
MongoDatabase database = server.GetDatabase("mydb");

‹-- это работает нормально

BsonDocument[] batch = {
                         new BsonDocument {
                                             { "name", "Bran" },
                                             { "loc", "10, 10" }
                                         },
                                        new BsonDocument {
                                            { "name", "Ayla" },
                                            { "loc", "0, 0" }
                                        }
            };

places.InsertBatch(batch);

‹-- эта часть как-то не так

places.EnsureIndex(IndexKeys.GeoSpatial("loca"));
var queryplaces = Query.WithinCircle("loca", 0, 0, 11);
var cursor = places.Find(queryplaces);
foreach (var hit in cursor)
{
    foreach (var VARIABLE in hit)
    {
        Console.WriteLine(VARIABLE.Value);
    }
}

‹-- Я думаю, что в этой части должны быть показаны оба документа, а теперь нет ни одного. Простая находка показывает их обоих. Был бы рад помощи.


person JustusTh    schedule 09.08.2011    source источник


Ответы (2)


пример ниже на C# (важно отметить порядок в массиве, который является долготой, широта- следует за более логичным порядком x, y в отличие от более часто используемой формы, где широта предшествует долготе):

1.) сначала ваш класс должен иметь это:

public double[] Location { get; set; }

public double Latitude
{
    get { return _latitude; }
    set
    {
        Location[1] = value;
        _latitude = value;
    }
}

public double Longitude
{
    get { return _longitude; }
    set
    {
        Location[0] = value;
        _longitude = value;
    }
}

public MyClass()
{
    Location = new double[2];
}

2.) тогда вот некоторый код, который поможет вам начать работу с официальным драйвером С# и выполнить вставку с использованием геоиндексации:

    /// <summary>
    /// Inserts object and creates GeoIndex on collection (assumes TDocument is a class
    /// containing an array double[] Location where [0] is the x value (as longitude)
    /// and [1] is the y value (as latitude) - this order is important for spherical queries.
    /// 
    /// Collection name is assigned as typeof(TDocument).ToString()
    /// </summary>
    /// <param name="dbName">Your target database</param>
    /// <param name="data">The object you're storing</param>
    /// <param name="geoIndexName">The name of the location based array on which to create the geoIndex</param>
    /// <param name="indexNames">optional: a dictionary containing any additional fields on which you would like to create an index
    /// where the key is the name of the field on which you would like to create your index and the value should be either SortDirection.Ascending
    /// or SortDirection.Descending. NOTE: this should not include geo indexes! </param>
    /// <returns>void</returns>
    public static void MongoGeoInsert<TDocument>(string dbName, TDocument data, string geoIndexName, Dictionary<string, SortDirection> indexNames = null)
    {
        Connection connection = new Connection(dbName);
        MongoCollection collection = connection.GetMongoCollection<TDocument>(typeof(TDocument).Name, connection.Db);
        collection.Insert<TDocument>(data);
        /* NOTE: Latitude and Longitude MUST be wrapped in separate class or array */
        IndexKeysBuilder keys = IndexKeys.GeoSpatial(geoIndexName);
        IndexOptionsBuilder options = new IndexOptionsBuilder();
        options.SetName("idx_" + typeof(TDocument).Name);
        // since the default GeoSpatial range is -180 to 180, we don't need to set anything here, but if
        // we wanted to use something other than latitude/longitude, we could do so like this:
        // options.SetGeoSpatialRange(-180.0, 180.0);

        if (indexNames != null)
        {
            foreach (var indexName in indexNames)
            {
                if (indexName.Value == SortDirection.Decending)
                {
                    keys = keys.Descending(indexName.Key);
                }
                else if (indexName.Value == SortDirection.Ascending)
                {
                    keys = keys.Ascending(indexName.Key);
                }
            }
        }

        collection.EnsureIndex(keys, options);

        connection.Db.Server.Disconnect();
    }


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Bson;
using MongoDB.Driver;

namespace MyMongo.Helpers
{
    public class Connection
    {
        private const string DbName = "";
        private const string Prefix = "mongodb://";
        //private const string Server = "(...):27017/";
        private const string Server = "localhost:27017/";
        private const string PassWord = "";
        private const string UserName = "";
        private const string Delimeter = "";
        //if using MongoHQ
        //private const string Delimeter = ":";
        //private const string Prefix = "mongodb://";
        //private const string DbName = "(...)";
        //private const string UserName = "(...)";
        //private const string Server = "@flame.mongohq.com:(<port #>)/";
        //private const string PassWord = "(...)";
        private readonly string _connectionString = string.Empty;

        public MongoDatabase Db { get; private set; }
        public MongoCollection Collection { get; private set; }

        public Connection()
        {
            _connectionString = Prefix + UserName + Delimeter + PassWord + Server + DbName;
        }

        public Connection(string dbName)
        {
            _connectionString = Prefix + UserName + Delimeter + PassWord + Server + DbName;
            Db = GetDatabase(dbName);
        }

        //mongodb://[username:password@]hostname[:port][/[database][?options]]
        public MongoDatabase GetDatabase(string dbName)
        {
            MongoServer server = MongoServer.Create(_connectionString);
            MongoDatabase database = server.GetDatabase(dbName);
            return database;
        }

        public MongoCollection<TDocument> GetMongoCollection<TDocument>(string collectionName, MongoDatabase db, SafeMode safeMode = null)
        {
            if (safeMode == null) { safeMode = new SafeMode(true); }
            MongoCollection<TDocument> result = db.GetCollection<TDocument>(collectionName, safeMode);
            return result;
        }
    }
}
person Jordan    schedule 09.08.2011
comment
спасибо, я думаю, что этот пример очень правильный, но немного продвинутый - person JustusTh; 10.08.2011
comment
вам нужно добавить индекс на каждую вставку? или достаточно добавить индекс в коллекцию монго в первый раз, и автоматически при каждой вставке индекс будет обновляться? - person diegosasw; 16.03.2018
comment
@iberodev этот ответ был написан очень давно - я не уверен, что он все еще актуален. - person Jordan; 19.03.2018

После поиска и поиска я нашел ответ здесь: https://github.com/karlseguin/pots-importer/blob/master/PotsImporter/NodeImporter.cs

Это нужно прочитать с моим первым фрагментом кода, так как это исправляет его.

  MongoCollection<BsonDocument> places =
               database.GetCollection<BsonDocument>("places");

            BsonDocument[] batch = {
                                       new BsonDocument { { "name", "Bran" }, { "loc", new BsonArray(new[] { 10, 10 }) } },
                                       new BsonDocument { { "name", "Ayla" }, { "loc", new BsonArray(new[] { 0, 0 }) } }
            };

            places.InsertBatch(batch);

            places.EnsureIndex(IndexKeys.GeoSpatial("loc"));

            var queryplaces = Query.WithinCircle("loc", 5, 5, 10);
            var cursor = places.Find(queryplaces);
            foreach (var hit in cursor)
            {
                Console.WriteLine("in circle");
                foreach (var VARIABLE in hit)
                {
                    Console.WriteLine(VARIABLE.Value);

                }
            }

В качестве пояснения: проблема с кодом в вопросе заключается в том, что информация о местоположении должна храниться не в виде строки, а в виде массива из 2 элементов (x, y).

person JustusTh    schedule 10.08.2011