如何查找任意深度的MongoDB字段名称

问题描述 投票:0回答:2

我将一些草率的 XML 数据导入到 Mongo 数据库中。每个文档都有嵌套子文档,深度约为 5-10 个。我想查找具有特定字段的特定值的文档,其中该字段可能出现在子文档中的任何深度(并且可能出现多次)。

我目前正在将每个文档拉入Python,然后搜索该字典,但如果我可以声明一个过滤器原型,其中数据库只会返回在其内容中某处具有特定字段名称值的文档,那就太好了。

这是一个示例文档:

{
    "foo": 1,
    "bar": 2,
    "find-this": "Yes!",
    "stuff": {
        "baz": 3,
        "gobble": [
            "wibble",
            "wobble",
            {
                "all-fall-down": 4,
                "find-this": "please find me"
            }                
        ],
        "plugh": {
            "plove": {
                "find-this": "Here too!"
            }
        }
   }
}

因此,我想查找具有“find-this”字段的文档,并且(如果可能)能够查找具有“find-this”字段特定值的文档。

mongodb recursion mongodb-query
2个回答
17
投票

您说得对,BSON 文档不是 XML 文档。由于 XML 被加载到由“节点”组成的树结构中,因此在任意键上进行搜索非常容易。

MonoDB 文档处理起来就没那么简单了,而且这在很多方面都是一个“数据库”,所以一般期望它的数据位置有一定的“一致性”,以便于“索引”和搜索.

尽管如此,这是可以做到的。但当然,这确实意味着在服务器上执行的递归过程,这意味着使用

$where
进行 JavaScript 处理。

作为一个基本的 shell 示例,但一般的

function
只是其他地方
$where
运算符的字符串参数:

db.collection.find({
  $where: function () {
    var findKey = "find-this",
      findVal = "please find me";

    function inspectObj(doc) {
      return Object.keys(doc).some(function (key) {
        if (typeof doc[key] == "object") {
          return inspectObj(doc[key]);
        } else {
          return key == findKey && doc[key] == findVal;
        }
      });
    }
    return inspectObj(this);
  },
});

所以基本上,测试对象中存在的键,看看它们是否与所需的“字段名称”和内容匹配。如果这些键之一恰好是“对象”,则递归到该函数并再次检查。

JavaScript

.some()
确保找到的“第一个”匹配将从搜索函数返回,给出
true
结果并返回“键/值”在某个深度存在的对象。

请注意,

$where
本质上意味着遍历整个集合,除非有其他有效的查询过滤器可以应用于集合上的“索引”。

因此请谨慎使用,或者根本不使用,只需将数据重新构造为更可行的形式即可。

但这会给你匹配的。


4
投票

这是一个示例,我用它来递归搜索文档结构中任意位置的键值:

db.getCollection('myCollection').find({

    "$where" : function(){

        var searchKey = 'find-this';
        var searchValue = 'please find me';

        return searchInObj(obj);

        function searchInObj(obj){                            
          for(var k in obj){       
            if(typeof obj[k] == 'object' && obj[k] !== null){
              if(searchInObj(obj[k])){
                return true;
              }
            } else {
              if(k == searchKey && obj[k] == searchValue){
                return true;
              }
            }          
          }                         
          return false;
        }       
    }    
})
© www.soinside.com 2019 - 2024. All rights reserved.