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

Posted

技术标签:

【中文标题】如何在任意深度查找 MongoDB 字段名称【英文标题】:How to find MongoDB field name at arbitrary depth 【发布时间】:2015-09-20 18:07:13 【问题描述】:

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

我目前正在将每个文档拉入 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”字段的特定值的文档。

【问题讨论】:

神圣的服务器端脚本,蝙蝠侠!我不知道你可以在数据库中运行 JS!这真的很酷,您的解决方案非常有意义。非常感谢! 哦,你知道吗?我敢打赌,您可以使用“或”$where 子句执行 find():让数据库使用自己的(快速)机制查找“key-to-search”和“value-to-search”,以查找密钥所在的位置顶层,并提供递归搜索JS函数,用于“key-to-search”不在顶层的所有节点。如果我可以让它工作,我会把它添加到这个问题中。 【参考方案1】:

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

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

不过,还是可以的。但这当然意味着在服务器上执行一个递归过程,这意味着 javascript 使用 $where 处理。

作为一个基本的 shell 示例,但一般的 function 只是其他任何地方的 $where 运算符的字符串参数:

db.collection.find(
  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 本质上意味着遍历您的整个集合,除非有一些其他有效的查询过滤器可以应用于集合上的“索引”。

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

但这会给你你的比赛。

【讨论】:

【参考方案2】:

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

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

【讨论】:

我知道这是一个旧答案,但obj 来自return searchInObj(obj); 的哪里? 如文档所述:“使用 this 或 obj 在 JavaScript 表达式或函数中引用文档”

以上是关于如何在任意深度查找 MongoDB 字段名称的主要内容,如果未能解决你的问题,请参考以下文章

如何使用聚合 MongoDB 查找具有两列的不同字段

在 MongoDB 中查找重复记录

如何仅在特定条件下执行 MongoDB 聚合阶段之一?

如何在任意逻辑状态图之间发送信号?

如何在mongodb中查找各种数组的“作者”字段?

如何使用多个条件查找查询在 MongoDB 中指定字段?