2015-10-17 52 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