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

时间:2011-07-22 13:38:19

标签: search mongodb field

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

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

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

我的想法是这样的

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

会给我示例元素。

感谢您的帮助。

8 个答案:

答案 0 :(得分:27)

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

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

如果您在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文档here

答案 1 :(得分:25)

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

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

这显然有一些缺点(主要是性能和复杂的架构)但会允许你需要的东西:

db.things.find({'params.value':"bar"})

答案 2 :(得分:20)

This answer对于类似的问题有你的解决方案,为了完整起见,我将在此重复。您可以使用$where运算符在MongoDB服务器上运行任意JavaScript,但需要注意的是,这将比几乎任何其他类型的查询慢得多。对于您的示例,它将是:

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

答案 3 :(得分:15)

可悲的是,之前的答案都没有解决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")
}}

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

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

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

答案 4 :(得分:2)

您可以使用递归函数执行此操作:

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');

答案 5 :(得分:2)

要进行文本搜索,您必须为集合创建文本索引。 有关更多信息,请查看mongo文档:indexes text

答案 6 :(得分:1)

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

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

其中/needle/是要在doc[key]

的值中查找的正则表达式

答案 7 :(得分:-8)

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

db.collection_name.find({'foo':"bar"})