MongoDB と MongoDBのC#ドライバー を使用しています。
最近、MongoDBのすべてのクエリで大文字と小文字が区別されることを発見しました。大文字と小文字を区別しない検索を行うにはどうすればよいですか?
私はこれを行う1つの方法を見つけました:
Query.Matches(
"FirstName",
BsonRegularExpression.Create(new Regex(searchKey,RegexOptions.IgnoreCase)));
これを行う最も簡単で安全な方法は、Linq
を使用することです。
var names = namesCollection.AsQueryable().Where(name =>
name.FirstName.ToLower().Contains("hamster"));
tutorial で説明されているように、ToLower
、ToLowerInvariant
、ToUpper
およびToUpperInvariant
はすべて、大文字と小文字を区別しない方法で一致を実行します。その後、Contains
やStartsWith
などのサポートされているすべての文字列メソッドを使用できます。
この例は以下を生成します:
{
"FirstName" : /hamster/is
}
i
オプションは、大文字と小文字を区別しません。
これを他のどの提案よりもはるかに単純に実装しました。ただし、この質問が古くなっているため、この機能はその時点では利用できなかった可能性があります。
Bson正規表現コンストラクターのオプションを使用して、大文字と小文字を区別しないで渡します。ソースコードを確認したところ、「i」で十分です。例えば。
var regexFilter = Regex.Escape(filter);
var bsonRegex = new BsonRegularExpression(regexFilter, "i");
Query.Matches("MyField", bsonRegex);
検索のためにレコードを2回保持する必要はありません。
次のようなものを使用してみてください:
Query.Matches("FieldName", BsonRegularExpression.Create(new Regex(searchKey, RegexOptions.IgnoreCase)))
おそらく、フィールドを2回保管する必要があります。1回は実際の値で、もう1回はすべて小文字で格納します。次に、大文字と小文字を区別しない検索のために小文字バージョンをクエリできます(クエリ文字列も小文字にすることを忘れないでください)。
このアプローチは、多くのデータベースシステムで機能します(または必要です)。正規表現ベースの手法(少なくともプレフィックスまたは完全一致の場合)よりも優れています。
I3arnonが答えたように、Queryableを使用して、大文字と小文字を区別しない比較/検索を行うことができます。私が見つけたのは、サポートされていないため、string.Equals()メソッドを使用できないことです。比較を行う必要がある場合、残念ながら、Contains()は適切ではないため、かなり長い間、解決策に苦労していました。
文字列の比較を行いたい場合は、.Equals()の代わりに==を使用してください。
コード:
var names = namesCollection.AsQueryable().Where(name =>
name.FirstName.ToLower() == name.ToLower());
fluent-mongo アドオンを使用して他の誰かが疑問に思っている場合は、Linqを使用してそのようなクエリを実行できます。
public User FindByEmail(Email email)
{
return session.GetCollection<User>().AsQueryable()
.Where(u => u.EmailAddress.ToLower() == email.Address.ToLower()).FirstOrDefault();
}
その結果、正しいJSクエリになります。残念ながら、String.Equals()はまだサポートされていません。
MongoDB 3.4以降の場合、推奨される方法はインデックスを使用することです。 https://jira.mongodb.org/browse/DOCS-11105?focusedCommentId=1859745&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-1859745 を参照してください
1.ロケールの照合(例: "en")を使用し、強度が1または2のインデックスを作成します https://docs.mongodb.com/を参照)。 manual/core/index-case-insensitive / 詳細については
例として:
大文字と小文字を区別しないために、強度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;
}
MongoDBの組み込みフィルターを使用することもできます。 mongoの一部のメソッドを使用するのが簡単になる場合があります。
var filter = Builders<Model>.Filter.Where(p => p.PropertyName.ToLower().Contains(s.ToLower()));
var list = collection.Find(filter).Sort(mySort).ToList();
これを行う方法は、以下に示すようにMongoDB.Bson.BsonJavaScriptクラスを使用することです
store.FindAs<Property>(Query.Where(BsonJavaScript.Create(string.Format("this.City.toLowerCase().indexOf('{0}') >= 0", filter.City.ToLower()))));