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

How to find MongoDB field name at arbitrary depth

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

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

这是一个示例文档:

{
    "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" 字段值的文档。

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

MonoDB文档处理起来不是那么简单,这在很多方面都是"database",所以一般希望有一定的"uniformity"数据位置,才能使它"index" 和搜索都很容易。

不过,这是可以做到的。但这当然意味着在服务器上执行递归过程,这意味着 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);
  }
)

所以基本上,测试对象中存在的键,看它们是否匹配所需的 "field name" 和内容。如果其中一个键恰好是 "object",则递归到函数中并再次检查。

JavaScript .some() 确保找到的 "first" 匹配将从搜索功能 return 给出 true 结果和 return在某个深度存在 "key/value" 的对象。

请注意,$where 本质上意味着遍历整个集合,除非有一些其他有效的查询过滤器可以应用于集合中的 "index"。

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

但这会给你匹配。

这是一个例子,我用它来递归搜索文档结构中任何地方的键值:

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