Мне интересно, как использовать нечувствительность к регистру для выражений $in.
Согласно официальному руководству MongoDB вы можете сделать это:
{ name: { $in: [ /^acme/i, /^ack/ ] } }
Я проверил это на Compass, и он работает нормально, поиск нечувствителен.
Мне нужно это с помощью драйвера Mongo на С#.
Я делаю это:
var array = new BsonArray(companyNames);
var filter = new BsonDocument { { "Name", new BsonDocument { { "$in", new BsonArray(array) }} } };
var result = _collection.Find(filter).ToList();
companyNames — это строка[]
Однако это возвращает мне только точные совпадения. Это очевидно, потому что я не включаю выражение «regex». Но я не знаю, как я могу включить регулярное выражение в строку.
Обходной путь — создать выражение $or с регулярным выражением для каждого названия компании.
Кто-нибудь знает, как это сделать?
Спасибо
С mongo-csharp-драйвер вы можете использовать MongoDB.Bson.BsonRegularExpression. Вы можете либо выполнить:
var arrayIn = new BsonArray().Add(
new BsonRegularExpression("^acme", "i")
).Add(
new BsonRegularExpression("^ack"));
var filter = new BsonDocument { { "name", new BsonDocument { { "$in", arrayIn }} } };
var cursor = collection.Find(filter).ToList();
Или вместо string
используйте регулярное выражение и RegexOptions:
var arrayIn = new BsonArray().Add(
new BsonRegularExpression(
new Regex(
"^acme", RegexOptions.IgnoreCase))
).Add(new BsonRegularExpression(
"^ack"));
вот элегантное решение с использованием текстового индекса в поле названия компании.
using MongoDB.Entities;
namespace StackOverflow
{
class Program
{
public class Company : Entity
{
public string Name { get; set; }
}
static void Main(string[] args)
{
new DB("test");
DB.Index<Company>()
.Key(c => c.Name, KeyType.Text)
.Option(o => o.Background = false)
.Create();
var c1 = new Company { Name = "Ackme" };
var c2 = new Company { Name = "Acme" };
var c3 = new Company { Name = "Lackme" };
var c4 = new Company { Name = "Hackme" };
c1.Save(); c2.Save(); c3.Save(); c4.Save();
var names = new[] { "ackme", "acme" };
var result = DB.SearchText<Company>(string.Join(" ", names));
}
}
}
заметьте, в приведенном выше примере используется удобная библиотека MongoDB.Entities. однако концепции те же, но синтаксис официального драйвера громоздкий по сравнению с приведенным выше.
Мое решение было перегруженным .In()
в качестве метода расширения, принимающим дополнительный параметр для нечувствительности к регистру:
public static class MongoExtensions
{
public static FilterDefinition<TDocument> In<TDocument>(
this FilterDefinitionBuilder<TDocument> builder,
Expression<Func<TDocument, object>> expr,
IEnumerable<string> values,
bool ignoreCase)
{
if (!ignoreCase)
{
return builder.In(expr, values);
}
var filters = values
.Select(v => builder.Regex(expr, new BsonRegularExpression($"^{Regex.Escape(v)}$", "i")));
return builder.Or(filters);
}
}
Тогда вы можете просто:
var filter = Builders<Companies>.Filter.In(c => c.Name, companyNames, true);
var result = _collection.Find(filter).ToList();
Имейте в виду, что у вас может быть только один текстовый индекс для коллекции. (docs.mongodb.com/manual/core/index-text/…)