您需要任何查询元素的“直接路径”,并且“数据”不是您需要在此处搜索的路径的“顶级”,而是“项目 1”或“项目 2”中的文档和“数据”是它的子元素。
基本情况是使用"dot notation",其中根元素“已知”至少可能存在,并且还要注意$in 运算符不仅仅用于匹配数组中的值,因为 MongoDB 确实如此不在乎。但是你需要一个嵌套的$elemMatch:
db.my_data.find({
"$or": [
{ "Item 1.data": {
"$elemMatch": {
"$elemMatch": { "$eq": "green" }
}
}},
{ "Item 2.data": {
"$elemMatch": {
"$elemMatch": { "$eq": "green" }
}
}}
]
})
没有“通配符”来匹配前面路径的一部分,因此有必要在$or 条件中声明完整路径以搜索文档中的每个可能路径。
如果写出所有可能的前缀键不切实际,那么您唯一的其他方法是使用带有 $where 的 JavaScript 评估来确定匹配的逻辑:
db.my_data.find(function() {
var doc = this;
delete doc._id;
var matched = false;
for ( k in doc ) {
matched = doc[k].data.some(function(el) {
return el.some(function(inner) {
return inner === "green";
});
});
if (matched) break;
}
return matched;
})
或者该逻辑的一些变体,以实际测试可能的元素与“数据”数组以包含您的“绿色”值。这不是一个很好的解决方案,因为$where 需要在每个文档上执行以评估条件,因此不能使用索引来过滤结果。这意味着扫描整个集合,基本上是最慢的方法。
还只是显示“shell快捷方式”来编写,否则function()内容只是作为“字符串”提交给$where的参数,用于pymongo或其他语言驱动程序,但基本上下文是它是在服务器上评估的 JavaScript 代码。
更好的是更改您的文档,以便始终有一条一致的路径指向您要查询的元素。如:
{
"items": [
{ "name": "Item 1", "data": [["green", 1]] },
{ "name": "Item 2", "data": [["blue", 9], ["green", 1]] }
]
}
然后你可以发出这个简单的查询:
db.my_data.find({ "items.data": { "$elemMatch": { "$elemMatch": { "$eq": "green" } } } })
由于“路径”始终为 "items.data",这允许仅针对该路径的单一条件来测试所有元素