在没有明确命名的情况下搜索MongoDB中任何字段的值

Max*_* L. 55 search field mongodb

我查看了MongoDB文档并搜索了这个问题,但无法找到合适的答案.所以,这就是我要找的东西.假设我有一个包含这样的元素的集合:

{
   "foo" : "bar",
   "test" : "test",
   "key" : "value",
}
Run Code Online (Sandbox Code Playgroud)

我想要实现的是通过搜索所有(可能除了有限多个;-))字段来找到一个元素.换句话说:给定查询,我不知道应该在哪个字段中找到查询.

我的想法是这样的

db.things.find({_ANY_ : "bar"}) 
Run Code Online (Sandbox Code Playgroud)

会给我示例元素.

谢谢您的帮助.

dav*_*son 30

要对所有字段进行文本搜索,首先必须在所有字段上创建文本索引.

正如mongodb文档所示,"为了允许对包含字符串内容的所有字段进行文本搜索,请使用通配符说明符($**)来索引包含字符串内容的所有字段."

如果您在mongo shell中工作(通过调用'mongo'从命令行执行),那么您可以使用此命令执行此操作,其中'collection'是您要使用的数据库中集合的名称.

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

第二个对象,即可{name:"TextIndex"}选...你实际上并不需要为索引命名,因为每个集合只能有一个文本索引(一次......你可以删除索引并创建新的索引)如果你想).

一旦在所有字段上创建了文本索引,就可以使用以下查询对象进行简单的文本搜索: { $text : { $search: <your string> } }

所以,如果你正在写一个javascript函数,你可能会做类似的事情:

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

有关控制搜索的各种方法的更多信息,请参阅此处有关文本搜索的mongodb文档

  • @dave-adelson 如何使用正则表达式?我尝试使用正则表达式,但它给出了异常“errmsg”:“\”$search\“类型错误。预期字符串,找到正则表达式”,查询:find({$text:{$search: /version/}} ) (2认同)

Tom*_*ing 27

这个答案对一个类似问题有解决方案,我将在这里重复的完整性.您可以使用$where运算符在MongoDB服务器上运行任意JavaScript,但需要注意的是,这将比几乎任何其他类型的查询慢得多.对于你的例子,它将是:

db.things.find({$where: function() {
    for (var key in this) {
        if (this[key] === "bar") {
            return true;
        }
    }
    return false;
}});
Run Code Online (Sandbox Code Playgroud)

  • “在版本 3.6 中进行了更改:$expr 运算符允许在查询语言中使用聚合表达式。$expr 比 $where 更快,因为它不执行 JavaScript,因此应在可能的情况下首选它。” - [来源](https://docs.mongodb.com/manual/reference/operator/query/where/) (2认同)

Rem*_*iet 26

如果没有单独检查应用程序端的文档或通过服务器端代码执行,这是不可能的.考虑将架构更改为:

{params:[{field:"foo", value:"bar"}, {field:"test", value:"test"}, {field:"key", value:"value"}]}
Run Code Online (Sandbox Code Playgroud)

这显然有一些缺点(主要是性能和复杂的架构),但将允许您通过以下方式:

db.things.find({'params.value':"bar"})
Run Code Online (Sandbox Code Playgroud)

  • 事实上正确的答案如何有两个downvotes? (5认同)

twb*_*boc 17

遗憾的是,以前的答案都没有解决mongo可以在数组或嵌套对象中包含嵌套值的事实.

这是正确的查询:

{$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")
}}
Run Code Online (Sandbox Code Playgroud)

由于在数组或嵌套对象上调用typeof将返回'object',这意味着查询将迭代所有嵌套元素并将遍历所有嵌套元素,直到找到具有值的键.

您可以使用嵌套值检查以前的答案,结果将远非理想.

对整个对象进行字符串化的效果要差得多,因为它必须逐个遍历所有内存扇区以尝试匹配它们.并在ram内存中创建一个对象的副本作为字符串(由于函数上下文已经有一个加载的对象,因此查询使用更多的ram和慢速都是低效的)

  • 我们可以重写if(obj [field] == value)like - if(typeof obj [field] =='string'&& obj [field] .contains(/ value /)).它提供更准确的搜索结果 (3认同)

Wad*_*les 6

使用$where与进行全表扫描相同,不能使用索引。我也无法让它工作,但是我确实发现这有效(它也相当于全表扫描):

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

哪里/needle/是一个正则表达式来查找的值doc[key]