1. ホーム
  2. mongodb

[解決済み] mongoDB の文字列フィールドの値の長さ

2022-02-18 09:15:04

質問

フィールドのデータ型はStringです。フィールド名の文字数が40文字以上のデータを取得したい。

以下のクエリを試しましたが、エラーが返りました。 1.

db.usercollection.find(
{$where: "(this.name.length > 40)"}
).limit(2);

output :error: {
    "$err" : "TypeError: Cannot read property 'length' of undefined near '40)' ",
    "code" : 16722
}

これは2.4.9で動作していますが、私のバージョンは2.6.5です。

どうすればいいですか?

MongoDB 3.6 以降の場合。

$expr 演算子を使用すると、クエリ言語内で集約式を使用できるようになります。 $strLenCP 演算子を使って、次のように文字列の長さをチェックします。

db.usercollection.find({ 
    "name": { "$exists": true },
    "$expr": { "$gt": [ { "$strLenCP": "$name" }, 40 ] } 
})


MongoDB 3.4 以降のバージョンに対応。

また、アグリゲーションフレームワークは $redact というパイプライン演算子で論理条件を処理することができます。 $cond 演算子を使用し、特殊な操作 $$KEEP を指定すると、論理的条件が真である文書を保持するか、または $$PRUNE を使用して、条件が false であったドキュメントを削除してください。

この操作は $project パイプラインで、コレクション内のフィールドを選択し、論理条件クエリの結果を保持する新しいフィールドを作成し、それに続く $match ただし $redact は単一のパイプラインステージを使用しており、より効率的です。

論理条件としては 文字列集計演算子 を使用することができます。 $strLenCP 演算子で文字列の長さをチェックします。もし長さが $gt が指定された場合、これは真正一致となり、そのドキュメントは "keep"されます。そうでない場合は、quot;pruned"され、廃棄されます。


上記の概念を示す、以下の集約操作の実行を考えてみましょう。

db.usercollection.aggregate([
    { "$match": { "name": { "$exists": true } } },
    {
        "$redact": {
            "$cond": [
                { "$gt": [ { "$strLenCP": "$name" }, 40] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    },
    { "$limit": 2 }
])


を使用する場合 $where のように、括弧を付けずにクエリを実行してみてください。

db.usercollection.find({$where: "this.name.length > 40"}).limit(2);

より良いクエリーは、フィールドの存在を確認し、次に長さを確認することです。

db.usercollection.find({name: {$type: 2}, $where: "this.name.length > 40"}).limit(2); 

または

db.usercollection.find({name: {$exists: true}, $where: "this.name.length > 
40"}).limit(2); 

MongoDBは非 $where クエリ操作前 $where 式と非 $where クエリ文は、インデックスを使用することができます。よりよいパフォーマンスを得るには、文字列の長さを別のフィールドとして保存し、それをもとにインデックスを作成したり検索したりすることです。 $where は、それに比べるとかなり遅くなります。JavaScriptの式を使うことをお勧めします。 $where 演算子は、他の方法でデータを構成できない場合、またはデータを扱う際の最後の手段として使用します。 データの小さなサブセット


を使用しない、別の高速なアプローチです。 $where 演算子は $regex 演算子を使用します。を検索する次のパターンを考えてみましょう。

db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2); 

備考 - から ドキュメント :

そのフィールドにインデックスが存在する場合は、MongoDB がその正規表現にマッチします。 式とインデックス内の値とを比較することで、この方法よりも高速になることがあります。 コレクションをスキャンします。さらに最適化されるのは、正規 式は「接頭辞式」であり、すべての潜在的な は同じ文字列から始まります。これにより、MongoDB は その接頭辞から「範囲」を求め、その範囲内の値に対してのみマッチングを行います。 のインデックスがその範囲に含まれます。

正規表現とは、先頭が カレット (^) または左アンカー (\A) の後に、単純な文字列が続きます。 記号を使用します。例えば、正規表現 /^abc.*/ は、以下のように最適化されます。 で始まるインデックスからの値のみにマッチします。 abc .

さらに /^a/, /^a.*/,/^a.*$/ は同等の という文字列がありますが、それぞれ異なる性能を持っています。これらの 式は、適切なインデックスが存在する場合はインデックスを使用します。 /^a.*/ であり、かつ /^a.*$/ は遅くなる。 /^a/ の後にスキャンを停止することができます。 がプレフィックスにマッチする。