$regex
注意
このページでは、自己管理型(Atlas Search 以外)配置に対する正規表現検索機能について説明します。MongoDB Atlas でホストされているデータに対して、MongoDB では、改良された全文検索ソリューションである Atlas Search を提供します。Atlas Search は独自の $regex
演算子を持ちます。詳細については、Atlas Search ドキュメントの $regex を参照してください。
定義
互換性
次の環境でホストされる配置には $regex
を使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
$regex
を使うには、以下の構文のいずれかを使います。
{ <field>: { $regex: /pattern/, $options: '<options>' } } { "<field>": { "$regex": "pattern", "$options": "<options>" } } { <field>: { $regex: /pattern/<options> } }
注意
$regex
を mongodump
と共に使用するためには、クエリ ドキュメントを一重引用符('{ ... }')で囲み、shell 環境とやり取りしないようにする必要があります。
クエリ ドキュメントは、フィールド名と演算子を引用符で囲むことを含む、拡張 JSON V 2 形式(緩和モード、標準モード、厳密モードのいずれか)である必要があります。以下がその例です。
mongodump -d=sample_mflix -c=movies -q='{"year": {"$regex": "20"}}'
MongoDBでは、正規表現オブジェクト(/pattern/
)を使用して正規表現を指定することもできます。
{ <field>: /pattern/<options> }
特定の構文の使用に関する制限については、「$regex と /pattern/ の構文」を参照してください。
次の <options>
は正規表現で使用できます。
オプション | 説明 |
---|---|
| 大文字と小文字を区別せずに一致します。例、「 大文字と小文字を区別しない正規表現一致の実行 」を参照してください。 |
| アンカーを含むパターン(開始が パターンにアンカーが含まれていない場合、または文字列値に改行文字が含まれていない場合( |
| エスケープされたり、文字クラスに含まれていたりしない限り、 さらに、エスケープされていないハッシュまたはパウンド(
|
| ドット記号( |
| Unicode をサポートします。このフラグは使用可能ですが、冗長です。デフォルトで |
注意
$regex
演算子はグローバル検索修飾子g
をサポートしていません。
動作
$regex と /pattern/ の構文
$in
式
$in
クエリ述語演算子に正規表現を含めるには、JavaScript 正規表現オブジェクトのみを使用できます( /pattern/
)。
以下に例を挙げます。
{ name: { $in: [ /^acme/i, /^ack/ ] } }
$in
演算子内では $regex
演算子式を使用できません。
フィールドの暗黙的な AND
条件
フィールドのクエリ条件をカンマで区切ったリストに正規表現を含めるには、$regex
演算子を使用します。例は次のとおりです。
{ name: { $regex: /acme.*corp/i, $nin: [ 'acmeblahcorp' ] } } { name: { $regex: /acme.*corp/, $options: 'i', $nin: [ 'acmeblahcorp' ] } } { name: { $regex: 'acme.*corp', $options: 'i', $nin: [ 'acmeblahcorp' ] } }
x
と s
オプション
x
オプションまたは s
オプションのいずれかを使用するには、$regex
演算子とともに $options
演算子式を使用する必要があります。たとえば、 i
オプションと s
オプションを指定するには、次のように両方とも $options
を使用する必要があります。
{ name: { $regex: /acme.*corp/, $options: "si" } } { name: { $regex: 'acme.*corp', $options: "si" } }
PCRE と JavaScript
JavaScript でサポートされていない正規表現で、 PCRE でサポートされている機能を使用するには、 $regex
演算子を使用して正規表現を文字列として指定する必要があります。
大文字と小文字を区別しない文字列を一致させるには次のとおり。
"(?i)"
は、大文字と小文字を区別しない一致を開始します。"(?-i)"
は、大文字と小文字を区別しない一致を終了します。
たとえば、正規表現"(?i)a(?-i)cme"
は、次の文字列と一致します。
"a"
または"A"
ではじまる文字列。これは、大文字と小文字を区別しない一致です。"cme"
で終了する文字列。これは大文字と小文字を区別する一致です。
以下の文字列は、例の正規表現と一致します。
"acme"
"Acme"
次の例では、$regex
演算子を使用して、正規表現 "(?i)a(?-i)cme"
と一致する name
フィールドの文字列を検索します。
{ name: { $regex: "(?i)a(?-i)cme" } }
バージョン 6.1 以降、MongoDB は、正規表現によるパターン一致を実装するために Perl 互換正規表現 (PCRE 2)ライブラリを使用します。Perl 互換正規表現 (PCRE2) の詳細については、 PCRE ドキュメントを参照してください。
$regex
および $not
$not
演算子は次の両方で論理 NOT
演算を実行できます。
正規表現オブジェクト(
/pattern/
)以下に例を挙げます。
db.inventory.find( { item: { $not: /^p.*/ } } ) $regex
演算子式以下に例を挙げます。
db.inventory.find( { item: { $not: { $regex: "^p.*" } } } ) db.inventory.find( { item: { $not: { $regex: /^p.*/ } } } )
インデックスの使用
$regex
クエリのインデックス使用とパフォーマンスは、クエリが大文字と小文字を区別するかしないかによって異なります。
大文字と小文字を区別するクエリ
大文字と小文字を区別する正規表現クエリでは、フィールドにインデックスが存在する場合、MongoDB は正規表現をインデックス内の値と照合します。これは、コレクションをスキャンよりも高速です。
正規表現が「プレフィックス式」の場合、さらに最適化を行うことができます。一致する可能性のあるものはすべて同じ文字列で始まるということを意味します。これにより、MongoDB はそのプレフィックスから「範囲」を構築し、その範囲に含まれるインデックスの値のみと一致させることができます。
正規表現は、キャレット(^
)または左アンカー(\A
)で始まり、その後に単純な記号の文字列が続く場合、「プレフィックス式」です。たとえば、正規表現 /^abc.*/
は、abc
で始まるインデックスの値のみと一致させることによって最適化されます。
さらに、 /^a/
、 /^a.*/
、および /^a.*$/
は同等の文字列と一致しますが、パフォーマンス特性は異なります。これらの式はすべて、適切なインデックスが存在する場合はインデックスを使用しますが、 /^a.*/
と /^a.*$/
は遅くなります。/^a/
はプレフィックスと一致した後、スキャンを停止することができます。
大文字と小文字を区別しないクエリ
大文字と小文字を区別しないインデックスでは、通常、$regex
クエリのパフォーマンスは向上しません。$regex
の実装は照合順序に対応していないため、大文字と小文字を区別しないインデックスを効率的に使用することはできません。
例
このセクションの例では、次の products
コレクションを使用します。
db.products.insertMany( [ { _id: 100, sku: "abc123", description: "Single line description." }, { _id: 101, sku: "abc789", description: "First line\nSecond line" }, { _id: 102, sku: "xyz456", description: "Many spaces before line" }, { _id: 103, sku: "xyz789", description: "Multiple\nline description" }, { _id: 104, sku: "Abc789", description: "SKU starts with A" } ] )
LIKE
一致を行う
次の例は、 sku
フィールドが "%789"
のようになっているすべてのドキュメントと一致します。
db.products.find( { sku: { $regex: /789$/ } } )
この例は、次の SQL の LIKE ステートメントと似ています。
SELECT * FROM products WHERE sku like "%789";
出力例:
[ { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 103, sku: 'xyz789', description: 'Multiple\nline description' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
大文字と小文字を区別しない正規表現一致の実行
次の例では、i
オプションを使用して、sku
の値が ABC
で始まるドキュメントに対して大文字と小文字を区別しない一致を実行します。
db.products.find( { sku: { $regex: /^ABC/i } } )
出力例:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
指定したパターンで始まる行の複数行一致
次の例では、 m
オプションを使用して、複数行の文字列に対して文字 S
で始まる行と一致させます。
db.products.find( { description: { $regex: /^S/, $options: 'm' } } )
出力例:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
m
オプションを指定しない場合、出力例は次のようになります。
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
$regex
パターンにアンカーが含まれていない場合、次の例のように、パターンは文字列全体に対して一致します。
db.products.find( { description: { $regex: /S/ } } )
出力例:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
「.
(ドット文字)」を使用して改行に合わせる
次の例では、 s
オプションを使用してドット文字(.
)が改行を含むすべての文字と一致するようにし、i
オプションを使用して大文字と小文字を区別しない一致を実行します。
db.products.find( { description: { $regex: /m.*line/, $options: 'si' } } )
出力例:
[ { _id: 102, sku: 'xyz456', description: 'Many spaces before line' }, { _id: 103, sku: 'xyz789', description: 'Multiple\nline description' } ]
s
オプションを指定しない場合、出力例は次のようになります。
[ { _id: 102, sku: 'xyz456', description: 'Many spaces before line' } ]
パターン内の空白を無視する
次の例では、x
オプションを使用して、一致するパターン内で #
で始まり、\n
で終わる空白とコメントは無視します。
var pattern = "abc #category code\n123 #item number" db.products.find( { sku: { $regex: pattern, $options: "x" } } )
出力例:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' } ]
文字列内の大文字と小文字を一致させるための正規表現の使用
次の例では、正規表現 "(?i)a(?-i)bc"
を使用して、次の内容を含む sku
フィールド文字列と一致させます。
"abc"
"Abc"
db.products.find( { sku: { $regex: "(?i)a(?-i)bc" } } )
出力例:
[ { _id: 100, sku: 'abc123', description: 'Single line description.' }, { _id: 101, sku: 'abc789', description: 'First line\nSecond line' }, { _id: 104, sku: 'Abc789', description: 'SKU starts with A' } ]
正規表現オプション拡張による ASCII 以外の文字との一致
バージョン 6.1 で追加。
デフォルトでは、特定の正規表現オプション(/b
や/w
など)は ASCII 文字のみを認識します。そのため、UTF-8 文字に対して正規表現の一致を実行すると、予期しない結果を引き起こすことがあります。
MongoDB 6.1 以降では、UTF-8 文字と一致させるために*UCP
正規表現オプションを指定できます。
重要
UCP オプションのパフォーマンス
*UCP
オプションを使用すると、*UCP
で一致を実行するためには複数のステージのテーブルルックアップが必要となるため、オプションが指定されていないクエリよりも遅くなります。
たとえば、 songs
コレクション内の次のドキュメントを考えてみましょう。
db.songs.insertMany( [ { _id: 0, "artist" : "Blue Öyster Cult", "title": "The Reaper" }, { _id: 1, "artist": "Blue Öyster Cult", "title": "Godzilla" }, { _id: 2, "artist" : "Blue Oyster Cult", "title": "Take Me Away" } ] )
次の正規表現クエリは、\b
オプションを使用して正規表現の一致を行います。\b
オプションは、単語の境界に一致します。
db.songs.find( { artist: { $regex: /\byster/ } } )
出力例:
[ { _id: 0, artist: 'Blue Öyster Cult', title: 'The Reaper' }, { _id: 1, artist: 'Blue Öyster Cult', title: 'Godzilla' } ]
上記の結果は予期できないもので、返された artist
フィールド内のどの単語も一致した文字列( yster
)で始まっていません。ドキュメント _id: 0
および _id: 1
の Ö
文字は UTF-8 文字であるため、一致を実行する時には無視されます。
期待される結果は、このクエリが何もドキュメントを返さないことです。
クエリが UTF-8 文字を認識できるようにするには、次のようにパターンの前に *UCP
オプションを指定します。
db.songs.find( { artist: { $regex: "(*UCP)/\byster/" } } )
このクエリでは何もドキュメントが返されず、期待した結果となりました。
Tip
正規表現パターンのエスケープ文字
*UCP
またはその他の正規表現オプションを指定する場合は、shell またはドライバーに適切なエスケープ文字を使用していることを確認してください。