MongoDB и C#: поиск без учета регистра

Я использую MongoDB и драйвер C# для MongoDB.

недавно я обнаружил, что все запросы в MongoDB чувствительны к регистру. Как я могу сделать поиск без учета регистра?

Я нашел один способ сделать это:

Query.Matches(
    "FirstName", 
    BsonRegularExpression.Create(new Regex(searchKey,RegexOptions.IgnoreCase)));

9 ответов


самый простой и безопасный способ сделать это с помощью Linq:

var names = namesCollection.AsQueryable().Where(name =>
    name.FirstName.ToLower().Contains("hamster"));

как поясняется в учебник ToLower, ToLowerInvariant, ToUpper и ToUpperInvariant все выполняют матчи нечувствительным к регистру способом. После этого вы можете использовать все поддерживаемые строковые методы, такие как Contains или StartsWith.

этот пример будет генерировать:

{
    "FirstName" : /hamster/is
}

на делает его нечувствительным к регистру.


Я просто реализовано это намного проще, чем любые другие предложения. Однако я понимаю, что из-за возраста этого вопроса эта функциональность, возможно, не была доступна в то время.

используйте параметры конструктора регулярных выражений Bson для передачи нечувствительности к регистру. Я просто взглянул на исходный код и обнаружил, что " я " - это все, что вам нужно. Например.

var regexFilter = Regex.Escape(filter);
var bsonRegex = new BsonRegularExpression(regexFilter, "i");

Query.Matches("MyField", bsonRegex);

вам не нужно дважды вести записи для поиска.


попробовать использовать что-то вроде этого:

Query.Matches("FieldName", BsonRegularExpression.Create(new Regex(searchKey, RegexOptions.IgnoreCase)))

вам, вероятно, придется хранить поле дважды, один раз с его реальным значением и снова во всех строчных буквах. Затем вы можете запросить строчную версию для поиска без учета регистра (не забудьте также записать строку запроса в нижнем регистре).

этот подход работает (или необходим) для многих систем баз данных, и он должен работать лучше, чем методы на основе регулярных выражений (по крайней мере, для префикса или точного соответствия).


Как ответил i3arnon, вы можете использовать Queryable для выполнения сравнения/поиска без учета регистра. Я обнаружил, что не могу использовать веревку.Метод Equals (), потому что он не поддерживается. Если вам нужно сделать сравнение, Contains (), к сожалению, не подходит, что заставило меня бороться за решение в течение довольно долгого времени.

для тех, кто хочет сделать сравнение строк, просто используйте == вместо .Равняется.)(

код:

var names = namesCollection.AsQueryable().Where(name =>
    name.FirstName.ToLower() == name.ToLower());

в случае, если кто-то еще задается вопросом, используя свободно-монго add-on, вы можете использовать Linq для запроса:

public User FindByEmail(Email email)
{
    return session.GetCollection<User>().AsQueryable()
           .Where(u => u.EmailAddress.ToLower() == email.Address.ToLower()).FirstOrDefault();
}

что приводит к правильному JS-запросу. К Сожалению, Стринг.Equals () пока не поддерживается.


вы также можете использовать встроенные фильтры MongoDB. Это может облегчить использование некоторых методов монго.

var filter = Builders<Model>.Filter.Where(p => p.PropertyName.ToLower().Contains(s.ToLower()));
var list = collection.Find(filter).Sort(mySort).ToList();

способ сделать это-использовать MongoDB.Бсына.Класс BsonJavaScript, как показано ниже

 store.FindAs<Property>(Query.Where(BsonJavaScript.Create(string.Format("this.City.toLowerCase().indexOf('{0}') >= 0", filter.City.ToLower()))));

для MongoDB 3.4+ рекомендуется использовать индексы. Смотри https://jira.mongodb.org/browse/DOCS-11105?focusedCommentId=1859745&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-1859745

я успешно ищу с нечувствительным к регистру: 1. Создание индекса с параметрами сортировки для локали (e.g: "en") и с силой 1 или 2. См.https://docs.mongodb.com/manual/core/index-case-insensitive/ для дальнейшего подробности

  1. использование тех же параметров сортировки при выполнении поиска в коллекции MongoDb.

пример:

создайте сортировку с силой 1 или 2 для нечувствительного к регистру

private readonly Collation _caseInsensitiveCollation = new Collation("en", strength: CollationStrength.Primary);

создать индекс. В моем случае я индексирую несколько полей:

private void CreateIndex()
{
    var indexOptions = new CreateIndexOptions {Collation = _caseInsensitiveCollation};
    var indexDefinition
        = Builders<MyDto>.IndexKeys.Combine(
            Builders<MyDto>.IndexKeys.Ascending(x => x.Foo),
            Builders<MyDto>.IndexKeys.Ascending(x => x.Bar));
    _myCollection.Indexes.CreateOne(indexDefinition, indexOptions);
}

при запросе убедитесь, что вы используете те же параметры:

public IEnumerable<MyDto> GetItems()
{
    var anyFilter = GetQueryFilter();
    var anySort = sortBuilder.Descending(x => x.StartsOn);  
    var findOptions = new FindOptions {Collation = _caseInsensitiveCollation};

    var result = _salesFeeRules
        .Find(anyFilter, findOptions)
        .Sort(anySort)
        .ToList();

    return result;
}