我将一些草率的XML数据导入Mongo数据库。每个Document都有嵌套的子文档,深度约为5-10。我想找到()具有特定字段特定值的文档,其中字段可能出现在子文档的任何深度(并且可能出现多次)。
我目前正在将每个Document拉入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”字段的特定值的文档。
答案 0 :(得分:10)
您在BSON文档的某些声明中是正确的不是XML文档。由于XML被加载到包含“节点”的树结构中,因此搜索任意键非常容易。
MonoDB文档的处理并不是那么简单,而且这在许多方面都是一个“数据库”,因此通常希望它具有一定的“统一性”数据位置,以便于“索引”和搜索。
尽管如此,它可以做到。但是,这当然意味着在服务器上执行递归过程,这意味着使用$where
进行JavaScript处理。
作为一个基本的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
结果并返回“某个深度处存在”键/值“的对象。” / p>
请注意,$where
实际上意味着遍历整个集合,除非有一些其他有效的查询过滤器可以应用于集合上的“索引”。
因此要小心使用,或者根本不使用,只需将数据重新编排成更可行的形式。
但是这会给你你的比赛。
答案 1 :(得分:2)
这是一个例子,我用它来在文档结构的任何地方递归搜索Key-Value:
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;
}
}
})