2017-08-16 13 views
3

私はMongoDB 3.2サーバーを持っています。私のコレクションには、次のようなドキュメントが含まれていますなぜこのRegExpクエリはすべての結果を返しますか?

{ 
    "name": "string", 
    "explicitMods": [ 
     "+48 to Blah", 
     "-13% to Blah", 
     "12 to 18 to Blah" 
    ] 
} 

私はこの書き込みをした場合:

myCollection.find({ "explicitMods":/悪い文字列/})

を私はゼロを取得します結果、期待どおり。

は、私は、この書き込みがあれば:

myCollection.findを({ "explicitModsは、":/ \ dは+ \にD + /})

私は、コレクション内のすべての文書を取得します。実際には12 to 18のような部分文字列を含む文書が必要なので、これは予期しないことです。正規表現を/\d+ to \d+z/に変更すると、正しく一致しません。

+0

質問を更新して、クエリが返すサンプルドキュメントを提供できますが、含まれたくないドキュメントはありますか? – JohnnyHK

+1

あなたのお問い合わせがうまくいくようです。だからあなたはその文書の 'explicitMods'をフィルタリングしようとしていますか? – Mikey

+0

"12〜18"の前後に他の文字を入れたくない場合は、正規表現の先頭に '^'を、または式の最後に '$'を置く必要があるかもしれません。 '/^\ d +〜\ d + $ /'のような式。それは助けるかもしれない? –

答えて

1

あなたが実際にあなたがそれを聞いて条件に合致文書を返し「正しく」を発行しているクエリ。つまり、テストしているプロパティの「少なくとも1つの」配列要素が実際にクエリの条件と一致しているということです。

このことから、我々は、2つの可能な結果を​​推測することができます

  1. あなたの目的にのみすべて配列エントリが条件を満たした文書を返すことです。

  2. 「ドキュメント内の配列」のエントリを「フィルタリング」するのは、条件を満たす結果のみを返すことです。

これらからさまざまなアプローチがあります。まず、実際にMongoDBのためのクエリ演算子が存在しないということです。これは、 "すべての"配列要素が "通常のクエリ"で指定された条件を満たす必要があることを要求します。したがって、ロジックを別の形式で適用する必要があります。

このようなオプションの1つは、$whereのJavaScript評価を使用して、配列の内容を検査する方法です。ここでは、あなたの条件をテストするためにArray.every()を適用することができます。これは実際にはいくつかの有用な作業を行っているので、通常のクエリフィルタに加えてです。

考えると、ソースドキュメントのように:

db.myCollection.find({ 
    "explicitMods": /\d+ to \d+/, 
    "$where": function() { return this.explicitMods.every(e => /\d+ to \d+/.test(e)) } 
    } 
}) 

のみを返します。

あなたの意図は、「すべて」の配列要素にマッチする「文書」を返すことだけです
/* 1 */ 
{ 
    "_id" : ObjectId("5993a35be38f41729f1d6501"), 
    "name" : "string", 
    "explicitMods" : [ 
     "+48 to Blah", 
     "-13% to Blah", 
     "12 to 18 to Blah" 
    ] 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("5993a35be38f41729f1d6502"), 
    "name" : "string", 
    "explicitMods" : [ 
     "12 to 18 to Blah" 
    ] 
} 

、次の文を発行一致する文書:

{ 
    "_id" : ObjectId("5993a35be38f41729f1d6502"), 
    "name" : "string", 
    "explicitMods" : [ 
     "12 to 18 to Blah" 
    ] 
} 

を使用する代替の場合では、MongoDBの集約フレームワークでは、一般にJavaScriptの解釈式よりも高速に適用される「ネイティブコード演算子」を使用した式が使用できます。しかし実際には、$redactなどの集計操作に適用可能な$regexの同等の「論理演算子」(SERVER-11947を参照)は存在しません。

したがって、ここで使用可能な唯一のアプローチは、配列要素が$unwindを使用して、非正規化されている「後」ではなく、通常のクエリ条件で$matchを使用することです:

db.myCollection.aggregate([ 
    // Match "possible" documents 
    { "$match": { "explicitMods": /\d+ to \d+/ } }, 

    // unwind to denormalize 
    { "$unwind": "$explicitMods" }, 

    // Match on the "array" items now as documents 
    { "$match": { "explicitMods": /\d+ to \d+/ } }, 

    // Optionally "re-group" back to documents with only matching array items 
    { "$group": { 
    "_id": "$_id", 
    "name": { "$first": "$name" }, 
    "explicitMods": { "$push": "$explicitMods" } 
    }} 
]) 

そして、その1が返され、「両方」の文書が、わずかまします配列項目が一致するものが挙げられる。もちろん

/* 1 */ 
{ 
    "_id" : ObjectId("5993a35be38f41729f1d6501"), 
    "name" : "string", 
    "explicitMods" : [ 
     "12 to 18 to Blah" 
    ] 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("5993a35be38f41729f1d6502"), 
    "name" : "string", 
    "explicitMods" : [ 
     "12 to 18 to Blah" 
    ] 
} 

あなたは、そのテーマの「ばらつき」を適用し、どの文書を決定するためにフィルタ条件に対する配列の「長さをテストする」ことができます返すために:それは$where使用して「ネイティブ事業者」と、元のオプションと同じことをしながら

db.myCollection.aggregate([ 
    { "$match": { "explicitMods": /\d+ to \d+/ } }, 
    { "$addFields": { "origSize": { "$size": "$explicitMods" } } }, 
    { "$unwind": "$explicitMods" }, 
    { "$match": { "explicitMods": /\d+ to \d+/ } }, 
    { "$group": { 
    "_id": "$_id", 
    "name": { "$first": "$name" }, 
    "origSize": { "$first": "$origSize" }, 
    "explicitMods": { "$push": "$explicitMods" }, 
    }}, 
    { "$redact": { 
    "$cond": { 
     "if": { 
     "$eq": [ 
      { "$size": "$explicitMods" }, 
      "$origSize" 
     ] 
     }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
    } 
    }} 
]) 

しかしを、$unwindなどの操作の一般的なコストは、それがユーティリティ疑問だので、かなり時間がかかりそうなります元のクエリよりも結果を生成するためのリソースが必要です。

関連する問題