使用下面的文档集合,我需要找到特定字段的文档 - 例如。 lev3_field2
(在下面的文档中)存在。
我尝试了以下操作,但这并没有返回任何结果,但某些文档中存在字段lev3_field2
。
db.getCollection('some_collection').find({"lev3_field2": { $exists: true, $ne: null } })
{
"_id" : ObjectId("5884de15bebf420cf8bb2857"),
"lev1_field1" : "139521721",
"lev1_field2" : "276183",
"lev1_field3" : {
"lev2_field1" : "4",
"lev2_field2" : {
"lev3_field1" : "1",
"lev3_field2" : {
"lev4_field1" : "1",
"lev4_field2" : "1"
},
"lev3_field3" : "5"
},
"lev2_field3" : {
"lev3_field3" : "0",
"lev3_field4" : "0"
}
}
}
update1 :这是一个示例,但是在真实文档中,不知道要查找的字段的父字段是什么。因此,我会寻找`levM_fieldN'而不是lev3_field2
。
update2 :速度不是我主要关注的问题,我可以使用相对慢一点的选项,因为主要功能是找到符合所讨论标准的文档,一旦文档是找到并且理解了模式,可以通过包含父键来重写查询以提高性能。
答案 0 :(得分:8)
要搜索嵌套文档中的键,需要递归迭代文档字段,可以借助MongoDB中的 $ where 方法在JavaScript中执行此操作 以下查询将搜索文档及其子文档中是否存在键名。
我已经用你给出的例子检查了这个,并且它工作得很好。
db.getCollection('test').find({ $where: function () {
var search_key = "lev3_field2";
function check_key(document) {
return Object.keys(document).some(function(key) {
if ( typeof(document[key]) == "object" ) {
if ( key == search_key ) {
return true;
} else {
return check_key(document[key]);
}
} else {
return ( key == search_key );
}
});
}
return check_key(this);
}}
);
答案 1 :(得分:3)
没有内置函数来迭代MongoDB中的文档键,但您可以使用MapReduce实现此功能。主要优点是所有代码都直接在MongoDB数据库中执行,而不是在js客户端中执行,因此没有网络开销,因此它应该比客户端js更快
这是脚本:
var found;
// save a function in MongoDB to iterate over documents key and check for
// key name. Need to be done only once
db.system.js.save({
_id: 'findObjectByLabel',
value: function(obj, prop) {
Object.keys(obj).forEach(function(key) {
if (key === prop) {
found = true
}
if (!found && typeof obj[key] === 'object') {
findObjectByLabel(obj[key], prop)
}
})
}
})
// run the map reduce fonction
db.ex.mapReduce(
function() {
found = false;
var key = this._id
findObjectByLabel(this, 'lev3_field2')
value = found;
if (found) {
// if the document contains the key we are looking for,
// emit {_id: ..., value: true }
emit(key, value)
}
},
function(key, values) {
return values
}, {
'query': {},
'out': {inline:1}
}
)
此输出(在4个示例文档上运行,只有一个包含' lev3_field2')
{
"results" : [
{
"_id" : ObjectId("5884de15bebf420cf8bb2857"),
"value" : true
}
],
"timeMillis" : 18,
"counts" : {
"input" : 4,
"emit" : 1,
"reduce" : 0,
"output" : 1
},
"ok" : 1
}
运行脚本,将其复制到文件名" script.js"例如,然后从你的shell运行
mongo databaseName < script.js
答案 2 :(得分:0)
这是因为您正在尝试查看嵌套字段是否存在。这是您想要的查询:
db.some_collection.find({"lev1_field3.lev2_field2.lev3_field2": { $exists: true, $ne: null } })