在MongoDB中搜索任何字段的值,而不显式命名它

dtcbnfnu  于 2023-01-12  发布在  Go
关注(0)|答案(8)|浏览(173)

我浏览了MongoDB的文档,在Google上搜索了这个问题,但没有找到合适的答案。所以,下面是我要找的。假设我有一个包含如下元素的集合:

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

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

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

会给我一个示例元素。
谢谢你的帮助。

qaxu7uf2

qaxu7uf21#

要在所有字段上执行文本搜索,首先必须在所有字段上创建文本索引。
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> } });
要获得更多关于控制搜索的各种方法的信息,请参见文本搜索here的mongodb文档

yks3o0rb

yks3o0rb2#

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

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

myzjeezk3#

如果不在应用程序端或通过服务器端代码执行单独检查文档,则无法执行此操作。请考虑将架构更改为:

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

这显然有一些缺点(主要是性能和poluted schema),但可以通过以下方式满足您的需要:

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

zpgglvta4#

遗憾的是,前面的答案都没有解决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将返回'object',这意味着查询将在所有嵌套元素上迭代,并将迭代所有元素,直到找到具有值的键。
您可以使用嵌套值检查以前的答案,结果将远远不是所期望的。
字符串化整个对象的性能要差得多,因为它必须一个接一个地遍历所有内存扇区,并在ram内存中创建一个字符串形式的对象副本(效率低,因为查询使用了更多的ram;速度慢,因为函数上下文已经加载了一个对象)

fiei3ece

fiei3ece5#

使用$where和执行全表扫描是一样的,不能使用索引。我也不能让它工作,但是我发现它工作了(它也相当于全表扫描):

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

其中/needle/是要在doc[key]的值中查找的正则表达式

s3fp2yjn

s3fp2yjn6#

你可以用递归函数来实现:

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

zazmityj7#

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

az31mfrm

az31mfrm8#

对MongoDB进行快速而粗略的全数据库搜索是通过export将数据库导出到JSON和grep

database="your-database-name" outdir="outdir-name" \
mongo --quiet $database --eval "db.getCollectionNames().join('\n')" | \
grep -v system.indexes | \
xargs -L 1 -I {} mongoexport -d $database -c {} --out $outdir/{}.json

grep "search-term" $outdir

当然,搜索词将同时匹配键名和值,但有时候这甚至很方便(例如,开发人员试图在大型文档的文档结构更改后查找字段)。
这种解决方案对于大规模数据库来说效率非常低,但是在只有测试数据的开发过程中非常方便。
MongoDB导出到JSON的源代码是Tom Boutell's answer for "How to export all collections in MongoDB?",包含更多细节和解释。

相关问题