MongoDB在列表列表中查找值

Gun*_*her 6 mongodb pymongo mongodb-query

我正在使用MongoDB搜索包含列表列表的元素,其中列表中的至少一个项目与搜索参数匹配.

这是我目前拥有的结构的一个例子.

{  
   "Item 1":{  
      "data":[  
         ["green", 1]
      ]
   },
   "Item 2":{  
      "data":[  
         ["blue", 9],
         ["green", 1]
      ]
   }
}
Run Code Online (Sandbox Code Playgroud)

我想搜索数据列表中值为"green"的所有项目.

我目前有这个:

my_data.find({'data': {'$in': ['green']}})
Run Code Online (Sandbox Code Playgroud)

但是,没有返回任何结果.

Bla*_*ven 8

您需要一个"直接路径"到任何查询元素,"数据"不是您需要在此处搜索的路径的"顶层",而是文档中的"项目1"或"项目2","数据"是其中的一个子元素.

基本情况是使用"点符号",其中根元素至少可能存在"已知",并且还注意到$in操作符不必仅仅匹配数组中的值,因为MongoDB不关心.但是你需要一个嵌套的$elemMatch代替:

db.my_data.find({
    "$or": [
        { "Item 1.data": { 
            "$elemMatch": { 
                "$elemMatch": { "$eq": "green" }
            }
        }},
        { "Item 2.data": {
            "$elemMatch": {
                "$elemMatch": { "$eq": "green" }
            }
        }}
    ]
})
Run Code Online (Sandbox Code Playgroud)

没有用于匹配前一路径的一部分的"通配符",因此有必要在$or条件内声明完整路径以搜索文档中的每个可能路径.

如果写出所有可能的前缀键是不切实际的,那么您唯一的另一种方法是使用JavaScript评估$where来确定匹配的逻辑:

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;
})
Run Code Online (Sandbox Code Playgroud)

或者使用"数据"数组实际测试可能元素以包含"绿色"值的逻辑的一些变体.这不是一个很好的解决方案,因为$where需要在每个文档上执行以评估条件,因此不能使用索引来过滤结果.这意味着扫描整个集合,基本上是最慢的方法.

也只是显示写入的"shell快捷方式",否则function()内容只是作为$wherepymongo或其他语言驱动程序的参数中的"字符串"提交,但基本上下文是它是在服务器上评估的JavaScript代码.

更好的是更改文档,以便始终存在要查询的元素的一致路径.如:

{
    "items": [
        { "name": "Item 1", "data": [["green", 1]] },
        { "name": "Item 2", "data": [["blue", 9], ["green", 1]] }
    ]  
}
Run Code Online (Sandbox Code Playgroud)

然后你可以发出这个简单的查询:

 db.my_data.find({ "items.data": { "$elemMatch": { "$elemMatch": { "$eq": "green" } } } })
Run Code Online (Sandbox Code Playgroud)

由于"路径"总是"items.data"允许仅针对该路径的单个条件来测试所有元素