web-dev-qa-db-ja.com

MongoDB:大文字と小文字を区別しないクエリを作成することは可能ですか?

例:

> db.stuff.save({"foo":"bar"});

> db.stuff.find({"foo":"bar"}).count();
1
> db.stuff.find({"foo":"BAR"}).count();
0
265
Luke Dennis

regex を使うことができます。

あなたの例ではそれは以下のようになります。

db.stuff.find( { foo: /^bar$/i } );

ただし、値を見つけるたびに追加料金が発生するのではなく、途中で値を小文字(または大文字)に変換することもできます。明らかにこれは人々の名前などには有効ではありませんが、おそらくタグのようなユースケースです。

298
rfunduk

更新:

元の答えは今では時代遅れです。 Mongodbは現在、多くの機能を備えた高度な全文検索をサポートしています。

元の答え:

正規表現の大文字と小文字を区別しないで/ iで検索すると、mongodbはインデックスで検索できないため、大きなデータセットに対するクエリには長時間かかることがあります。

小さなデータセットでも、それほど効率的ではありません。クエリの保証よりもはるかに大きいCPUヒットを受けます。これは、スケールを達成しようとしている場合に問題になる可能性があります。

代わりに、大文字のコピーを保存してそれを検索することもできます。たとえば、大文字と小文字が混在するユーザー名を持つUserテーブルがありますが、idはユーザー名の大文字のコピーです。これは大文字と小文字を区別する複製が不可能であることを保証します( "Foo"と "foo"の両方を持つことは許されないでしょう)。

メッセージ本文のようにフィールドが大きい場合は、データを複製することはおそらくお勧めできません。その場合は、Apache Luceneのような無関係のインデクサーを使用するのが最善の選択肢だと思います。

190
Dan

前の例は次の点に注意してください。

db.stuff.find( { foo: /bar/i } );

barを含むすべてのエントリがクエリ(bar1、barxyz、openbar)と一致するようになります。auth関数でのユーザー名検索では非常に危険です。 ..

次のように適切な正規表現構文を使用して、検索語のみに一致させる必要があるかもしれません。

db.stuff.find( { foo: /^bar$/i } );

正規表現の構文ヘルプについては、 http://www.regular-expressions.info/ を参照してください。

58
jflaflamme

あなたが変数から正規表現を作成する必要があるなら、これはそれをするためのはるかに良い方法です: https://stackoverflow.com/a/10728069/309514

その後、次のようにすることができます。

var string = "SomeStringToFind";
var regex = new RegExp(["^", string, "$"].join(""), "i");
// Creates a regex of: /^SomeStringToFind$/i
db.stuff.find( { foo: regex } );

これは、よりプログラム的になるという利点があります。あるいは、再利用する場合は、事前にコンパイルすることでパフォーマンスを向上させることができます。

56
Fotios

MongoDB以降、大文字と小文字を区別しないで高速検索を実行するための推奨される方法は、大文字と小文字を区別しないインデックスを使用することです。

私は創設者の一人に個人的に電子メールを送ってこれを機能させてください、そして彼はそれを実現させました!それは 2009年以来のJIRAの問題 であり、そして多くがこの機能を要求しています。これがどのように動作するのかです:

大文字と小文字を区別しないインデックスは、1または2の強度を持つ 照合 を指定して作成されます。大文字と小文字を区別しないインデックスは、次のように作成できます。

db.cities.createIndex(
  { city: 1 },
  { 
    collation: {
      locale: 'en',
      strength: 2
    }
  }
);

コレクションを作成するときに、コレクションごとに既定の照合順序を指定することもできます。

db.createCollection('cities', { collation: { locale: 'en', strength: 2 } } );

どちらの場合も、大/小文字を区別しない索引を使用するには、索引またはコレクションの作成時に使用したのと同じ照合順序をfind操作に指定する必要があります。

db.cities.find(
  { city: 'new york' }
).collation(
  { locale: 'en', strength: 2 }
);

これにより、 "New York"、 "new york"、 "New york"などが返されます。

その他の注意

  • この場合全文検索を使用することを提案する回答は間違っています(そして潜在的に危険です)。問題は、大文字と小文字を区別しないクエリを作成することです。 username: 'bill'BILLまたはBillと一致しますが、全文検索クエリではありません。これは 語幹付きbillの単語(Billsbilledなど)とも一致します。
  • 正規表現を使うことを提案する答えは遅い、なぜならインデックスを使っても ドキュメンテーション状態

    「大文字と小文字を区別しない正規表現クエリでは、一般にインデックスを効果的に使用できません。$ regexの実装では照合順序が認識されず、大文字と小文字を区別しないインデックスを利用できません。」

    $regexの回答も ユーザー入力インジェクション のリスクを冒しています。

32
user3413723
db.zipcodes.find({city : "NEW YORK"}); // Case-sensitive
db.zipcodes.find({city : /NEW york/i}); // Note the 'i' flag for case-insensitivity
16
rshivamca

TL、DR

Mongoでこれを行う正しい方法

使用しない正規表現

自然に移動し、mongodbの作り付けのインデックスを使用して検索

ステップ1 :

db.articles.insert(
   [
     { _id: 1, subject: "coffee", author: "xyz", views: 50 },
     { _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
     { _id: 3, subject: "Baking a cake", author: "abc", views: 90  },
     { _id: 4, subject: "baking", author: "xyz", views: 100 },
     { _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
     { _id: 6, subject: "Сырники", author: "jkl", views: 80 },
     { _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
     { _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
   ]
)

ステップ2 :

検索したいTEXTフィールドのどちらかにインデックスを作成する必要があります。

db.articles.createIndex( { subject: "text" } )

ステップ3:

db.articles.find( { $text: { $search: "coffee",$caseSensitive :true } } )  //FOR SENSITIVITY
db.articles.find( { $text: { $search: "coffee",$caseSensitive :false } } ) //FOR INSENSITIVITY
14
vijay
db.company_profile.find({ "companyName" : { "$regex" : "Nilesh" , "$options" : "i"}});
8
Nilesh

Mongo(現在のバージョン2.0.0)はインデックス付きフィールドに対して大文字と小文字を区別しない検索を許可していません - 彼らのドキュメント を見てください。インデックスのないフィールドでは、他の答えにリストされている正規表現は問題ないはずです。

8
Aidan Feldman

最良の方法はあなたの選択した言語にあります。あなたのオブジェクトのためのモデルラッパーを作成するとき、save()メソッドがあなたが検索するフィールドのセットを通して反復するようにしてください。これらのフィールドのセットは、検索に使用される小文字の対応物を持つ必要があります。

オブジェクトが再度保存されるたびに、小文字のプロパティがチェックされ、メインプロパティへの変更があれば更新されます。これにより、効率的に検索できるようになりますが、毎回lcフィールドを更新するのに必要な余分な作業は隠されます。

小文字のフィールドは、キー:値オブジェクトストア、または単に接頭辞lc_が付いたフィールド名です。 2番目の方法を使用して、照会を単純化しています(深いオブジェクト照会は時に混乱を招く可能性があります)。

注意:あなたはlc_フィールドをインデックスしたいのですが、それらが基づいているメインフィールドではありません。

6
RobKohr

Regexベースのクエリを使用するときに注意することが1つ非常に重要なこと - あなたがログインシステムのためにこれをしているとき、 あなたが探しているすべての一文字をエスケープする ^と$演算子を忘れないでください。 LodashにはこのためのNice関数があります 。すでに使用している必要があります。

db.stuff.find({$regex: new RegExp(_.escapeRegExp(bar), $options: 'i'})

どうして?ユーザーが自分のユーザー名として.*を入力したとします。これはすべてのユーザー名と一致し、ユーザーのパスワードを推測するだけでログインが可能になります。

5
Nick Kamer

Mongooseを使用してこれは私のために働いた:

var find = function(username, next){
    User.find({'username': {$regex: new RegExp('^' + username, 'i')}}, function(err, res){
        if(err) throw err;
        next(null, res);
    });
}
5
ChrisRich

"Table"の "column"を検索し、大文字と小文字を区別しないで検索したいとします。最も効率的な方法は以下の通りです。

//create empty JSON Object
mycolumn = {};

//check if column has valid value
if(column) {
    mycolumn.column = {$regex: new RegExp(column), $options: "i"};
}
Table.find(mycolumn);

上記のコードでは、検索値をRegExとして追加し、オプションとして "i"で設定された鈍感な条件で検索します。

ではごきげんよう。

5
Ankur Soni

大文字と小文字を区別しないインデックスを使用できます。

次の例では、デフォルトの照合順序を指定せずにコレクションを作成し、大文字と小文字を区別しない照合順序で[名前]フィールドにインデックスを追加します。 nicodeの国際コンポーネント

/* strength: CollationStrength.Secondary
* Secondary level of comparison. Collation performs comparisons up to secondary * differences, such as diacritics. That is, collation performs comparisons of 
* base characters (primary differences) and diacritics (secondary differences). * Differences between base characters takes precedence over secondary 
* differences.
*/
db.users.createIndex( { name: 1 }, collation: { locale: 'tr', strength: 2 } } )

インデックスを使用するには、クエリで同じ照合順序を指定する必要があります。

db.users.insert( [ { name: "Oğuz" },
                            { name: "oğuz" },
                            { name: "OĞUZ" } ] )

// does not use index, finds one result
db.users.find( { name: "oğuz" } )

// uses the index, finds three results
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 2 } )

// does not use the index, finds three results (different strength)
db.users.find( { name: "oğuz" } ).collation( { locale: 'tr', strength: 1 } )

あるいは、デフォルトの照合順序でコレクションを作成することもできます。

db.createCollection("users", { collation: { locale: 'tr', strength: 2 } } )
db.users.createIndex( { name : 1 } ) // inherits the default collation
3
Gencebay D.

集約フレームワークはmongodb 2.2で導入されました。文字列演算子 "$ strcasecmp"を使用すると、文字列間で大文字と小文字を区別しないで比較できます。正規表現を使用するよりもお勧めで簡単です。

これが集約コマンド演算子に関する公式文書です。 https://docs.mongodb.com/manual/reference/operator/aggregation/strcasecmp/#exp._S_strcasecmp

3
Jogue Wasin

変数を検索してそれをエスケープするには:

const escapeStringRegexp = require('escape-string-regexp')
const name = 'foo'
db.stuff.find({name: new RegExp('^' + escapeStringRegexp(name) + '$', 'i')})   

変数をエスケープすると、 '。*'などの正規表現による攻撃からクエリが保護されます。

escape-string-regexp

2
davidivad

RegExpを使用します。他のオプションが機能しない場合は、RegExpが適切なオプションです。文字列の大文字と小文字を区別しません。

var username = new RegExp("^" + "John" + "$", "i");;

クエリでユーザー名を使用してから、完了です。

私もそれがあなたのために働くことを願っています。ではごきげんよう。

0
Gouri Shankar

あなたがmongoのドキュメントで見ることができるように - バージョン3.2からデフォルトで$textインデックスは大文字と小文字を区別しません: https://docs.mongodb.com/manual/core/index-text/#text-index-case-insensitivity

テキストインデックスを作成する および クエリに$ text演算子を使用する

0
avalanche1

C#では、フィルタを使うのは私にとってはうまくいきます。

string s = "searchTerm";
    var filter = Builders<Model>.Filter.Where(p => p.Title.ToLower().Contains(s.ToLower()));
                var listSorted = collection.Find(filter).ToList();
                var list = collection.Find(filter).ToList();

私はメソッドが戻りが起こった後に呼ばれると信じているので私はまだこれをテストしていないのでそれはインデックスを使うかもしれません。

これはまたの問題を避けます

var filter = Builders<Model>.Filter.Eq(p => p.Title.ToLower(), s.ToLower());

そのmongodbはp.Title.ToLower()がプロパティであると考え、正しくマッピングされません。

0
A_Arnold

これらは文字列検索でテスト済みです

{'_id': /.*CM.*/}               ||find _id where _id contains   ->CM
{'_id': /^CM/}                  ||find _id where _id starts     ->CM
{'_id': /CM$/}                  ||find _id where _id ends       ->CM

{'_id': /.*UcM075237.*/i}       ||find _id where _id contains   ->UcM075237, ignore upper/lower case
{'_id': /^UcM075237/i}          ||find _id where _id starts     ->UcM075237, ignore upper/lower case
{'_id': /UcM075237$/i}          ||find _id where _id ends       ->UcM075237, ignore upper/lower case
0
Ar maj

私は同様の問題に直面していましたが、これが私のために働いたものです。

  const flavorExists = await Flavors.findOne({
    'flavor.name': { $regex: flavorName, $options: 'i' },
  });
0
Woppi

Golangを使っていて、mongodbとmgoを使って大文字と小文字を区別して全文検索をしたいという方は godoc globalsign library

collation := &mgo.Collation{
    Locale:   "en",
    Strength: 2, 
}


err := collection.Find(query).Collation(collation)
0
okandas

大文字と小文字を区別しない正規表現用の単純なFuncを作成しました。これを私のフィルタで使用します。

private Func<string, BsonRegularExpression> CaseInsensitiveCompare = (field) => 
            BsonRegularExpression.Create(new Regex(field, RegexOptions.IgnoreCase));

その後、次のように単純にフィールドをフィルタリングします。

db.stuff.find({"foo": CaseInsensitiveCompare("bar")}).count();
0
Nitesh