2015-10-17 70 views
5

我正在使用MongoDB搜索包含列表中至少有一个项目与搜索参数匹配的列表的元素。MongoDB在列表中查找值

这是我目前具有的结构的一个例子。

{ 
    "Item 1":{ 
     "data":[ 
     ["green", 1] 
     ] 
    }, 
    "Item 2":{ 
     "data":[ 
     ["blue", 9], 
     ["green", 1] 
     ] 
    } 
} 

我想搜索具有在数据列表中的值“绿色”的所有项目。

目前,我有这样的:

my_data.find({'data': {'$in': ['green']}}) 

但是,不返回任何结果。

+1

这可能有帮助。 http://stackoverflow.com/questions/17303833/mongodb-nested-array-query – lostintranslation

回答

5

你需要一个“直接路径”来查询元素,“数据”不是你需要在这里搜索的路径的“最高级别”,而是“项目1”或“项目2 “文件内的”数据“是其中的一个子元素。

基本情况是使用"dot notation"其中根元素是“已知”的,至少可能存在,并且还要注意,因为MongoDB不关心,因此$in运算符不需要仅仅匹配数组中的值。但是,您将需要一个嵌套$elemMatch代替:

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

有没有“通配符”那么,有必要说明的$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; 
}) 

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

也只是展示了“外壳程序快捷方式”,以书面形式,因为否则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"这允许一个单一的condtion只是为了测试所有元素路径

+0

谢谢你真正全面的答案。这是一个巨大的帮助。 – Gunther