web-dev-qa-db-ja.com

明示的に名前を付けずにMongoDBのフィールドの値を検索する

MongoDBのドキュメントを見て、この質問をグーグルで検索しましたが、適切な答えを見つけることができませんでした。だから、ここに私が探しているものがあります。次のような要素を持つコレクションがあると仮定します。

{
   "foo" : "bar",
   "test" : "test",
   "key" : "value",
}

私が達成したいのは、すべてのフィールドを検索することで要素を見つけることです(おそらく、有限の多くの;-)を除く)。言い換えると、クエリが与えられた場合、どのフィールドでクエリが検索されるべきかわかりません。

私の考えでは、このようなもの

db.things.find({_ANY_ : "bar"}) 

要素の例を示します。

ご協力ありがとうございました。

54
Max L.

すべてのフィールドでテキスト検索を行うには、最初にすべてのフィールドでテキストインデックスを作成する必要があります。

mongodb documentation が示すように、「文字列コンテンツを含むすべてのフィールドでテキスト検索を可能にするには、ワイルドカード指定子($ **)を使用して、文字列コンテンツを含むすべてのフィールドにインデックスを付けます。」

mongoシェル(コマンドラインから 'mongo'を呼び出して実行する)内で作業している場合は、このコマンドを使用して実行できます。'collection 'は使用するdb内のコレクションの名前です。

db.collection.createIndex({ "$**": "text" },{ name: "TextIndex" })

2番目のオブジェクト、つまり_{name:"TextIndex"}_はオプションです...コレクションごとに1つのテキストインデックスしか存在できないため、インデックスに実際に名前を付ける必要はありません(一度に...インデックスを作成し、必要に応じて新しいインデックスを作成します)。

すべてのフィールドにテキストインデックスを作成したら、次のクエリオブジェクトを使用して簡単なテキスト検索を実行できます。_{ $text : { $search: <your string> } }_

そのため、javascript関数を作成している場合は、次のようなことを行うことができます。

var cursor = db.collection(<collection_name>).find({ $text: { $search: <your string> } });

検索を制御するさまざまな方法の詳細については、テキスト検索に関するmongodbのドキュメントを参照してください here

29
dave adelson

この回答 同様の質問に対する解決策があります。完全を期すためにここで繰り返します。 $where MongoDBサーバーで任意のJavaScriptを実行する演算子。ただし、これは他のほとんどの種類のクエリよりもはるかに遅いことに注意してください。たとえば、次のようになります。

db.things.find({$where: function() {
    for (var key in this) {
        if (this[key] === "bar") {
            return true;
        }
        return false;
    }
}});
26
Tom Panning

これは、個別にドキュメントをアプリ側で検査するか、サーバー側のコードを実行することなく行うことはできません。スキーマを次のように変更することを検討してください。

{params:[{field:"foo", value:"bar"}, {field:"test", value:"test"}, {field:"key", value:"value"}]}

これには明らかにいくつかの欠点(パフォーマンスと汚染されたスキーマがほとんど)がありますが、必要なものは許可されます

db.things.find({'params.value':"bar"})
26
Remon van Vliet

悲しいことに、これまでの回答はどれも、mongoが配列またはネストされたオブジェクトにネストされた値を含むことができるという事実に対処していません。

これIS正しいクエリ:

{$where: function() {
    var deepIterate = function  (obj, value) {
        for (var field in obj) {
            if (obj[field] == value){
                return true;
            }
            var found = false;
            if ( typeof obj[field] === 'object') {
                found = deepIterate(obj[field], value)
                if (found) { return true; }
            }
        }
        return false;
    };
    return deepIterate(this, "573c79aef4ef4b9a9523028f")
}}

配列またはネストされたオブジェクトでtypeofを呼び出すと 'object'が返されるため、クエリはネストされたすべての要素を反復処理し、値を持つキーが見つかるまですべてを反復処理します。

ネストされた値を使用して以前の回答を確認できますが、結果は望みどおりにはなりません。

オブジェクト全体を文字列化することは、すべてのメモリセクタを1つずつ照合して照合する必要があるため、パフォーマンスがはるかに低くなります。オブジェクトのコピーをRAMメモリ内の文字列として作成します(関数コンテキストには既にロードされたオブジェクトがあるため、クエリはより多くのRAMを使用し、遅いため、非効率的です)

17
twboc

再帰関数でそれを行うことができます:

var recursiveSearch = function(query) {
    db.test_insert.find().forEach(function(items) {
        var i = 0;
        var recursiveFunc = function(itemsArray, itemKey) {
            var itemValue = itemsArray[itemKey];
            if(itemValue === query) { 
                printjson(items);
            }       

            if(typeof itemValue === "object") {
                Object.keys(itemValue).forEach(function(itemValueKey) {
                    recursiveFunc(itemValue, itemValueKey);
                });
            }
        };
        Object.keys(items).forEach(function(item){
            recursiveFunc(items, item);
        });
    });
};

recursiveSearch('your string');
3
RoXuS

$ where を使用することは、全表スキャンを実行することと同じであり、インデックスを使用できません。私はそれを動作させることもできませんでしたが、これが動作していることを発見しました(また、フルテーブルスキャンと同等の動作をします):

db.collection.find().forEach(function(doc){
for (var key in doc) {
    if ( /needle/.test(doc[key]) )
        printjson(doc);
    }
});

ここで、/needle/は、doc[key]の値で検索する正規表現です。

3
Waddles

テキスト検索を行うには、コレクションのテキストインデックスを作成する必要があります。詳細については、mongoのドキュメントをご覧ください: indexes text

2
Salim Hamidi