2011-06-17 75 views
2

看起來很簡單的任務,對我來說是一個挑戰。mongodb - 檢索數組子集

我有以下MongoDB的結構:

{ 
(...) 
"services": { 
    "TCP80": { 
     "data": [{ 
      "status": 1, 
      "delay": 3.87, 
      "ts": 1308056460 
     },{ 
      "status": 1, 
      "delay": 2.83, 
      "ts": 1308058080 
     },{ 
      "status": 1, 
      "delay": 5.77, 
      "ts": 1308060720 
     }] 
    } 
}} 

現在,下面的查詢將返回整個文檔:

{ 'services.TCP80.data.ts':{$gt:1308067020} } 

我不知道 - 這可能對我來說,只接收那些「數據」數組條目匹配$ gt條件(種類的收縮文檔)?

我正在考慮MapReduce,但甚至找不到關於如何將外部參數(timestamp)傳遞給Map()函數的單個示例。 (此功能已添加到1.1.4中https://jira.mongodb.org/browse/SERVER-401

此外,總是有一種替代方法來編寫storedJs函數,但由於我們提到的大量數據,db-locks在這裏是不能容忍的。

最有可能我得的結構重新設計的東西1級深,如:

{ 
    status:1,delay:3.87,ts:138056460,service:TCP80 
},{ 
    status:1,delay:2.83,ts:1308058080,service:TCP80 
},{ 
    status:1,delay:5.77,ts:1308060720,service:TCP80 
} 

但DB將急劇增長,因爲「服務」是唯一的,這將追加每個許多選項之一文件。

請指教!

在此先感謝

+0

至於「傳遞參數映射函數」,從你鏈接到的問題:'res = t.mapReduce(m,r,{mapparams:[2,2]});'https:// github。 com/mongodb/mongo/commit/123cd0eb6734f397ebf4236e0779d056243446d4#L1R38 –

+0

感謝Thomas, 至於我的解決方案 - 我目前堅持mongo的GROUP函數,它比mapreduce具有性能優勢,支持外部變量(通過'cond'參數)和允許我做任何類型的子集檢索我喜歡 – FlegmatoidZoid

回答

1

這目前不支持。默認情況下,除非使用字段限制或$ slice操作符,否則將始終接收整個文檔/數組。目前這些工具不允許根據搜索條件過濾數組元素。

你應該看這個請求的方式來做到這一點:https://jira.mongodb.org/browse/SERVER-828

0

我試圖做同樣的事情。我嘗試了使用GROUP函數的建議,但我無法保持嵌入的文檔單獨存在,或者做了不正確的事情。

我需要通過ID來獲取嵌入式文檔的子集。以下是我做到了使用的Map/Reduce:

db.parent.mapReduce(
    function(parent_id, child_ids){ 
    if(this._id == parent_id) 
     emit(this._id, {children: this.children, ids: child_ids}) 
    }, 
    function(key, values){ 
    var toReturn = []; 

    values[0].children.forEach(function(child){ 
     if(values[0].ids.indexOf(product._id.toString()) != -1) 
     toReturn.push(child); 
    }); 
    return {children: toReturn}; 
    }, 
    { 
    mapparams: [ 
     "4d93b112c68c993eae000001", //example parent id 
     ["4d97963ec68c99528d000007", "4debbfd5c68c991bba000014"] //example embedded children ids 
    ] 
    } 
).find() 

我抽象我的收藏叫「父」,它的嵌入式文件「孩子」。我傳入兩個參數:父文檔ID和我想要從父文檔檢索的嵌入文檔ID的數組。這些參數作爲第三個參數傳遞給mapReduce函數。

在map函數中,我找到了集合中的父文檔(我很確定它使用了_id索引)並將其id和children發送到reduce函數。

在reduce函數中,我將傳入的文檔和循環遍歷每個孩子,收集具有所需ID的孩子。循環遍歷所有的孩子並不理想,但我不知道在嵌入式文檔上通過ID找到另一種方法。

我還假設在reduce函數中,只有一個文檔發出,因爲我正在使用ID進行搜索。如果您希望有多個parent_id匹配,那麼您將不得不遍歷reduce函數中的values陣列。

我希望這可以幫助那裏的人,因爲我到處搜索並沒有結果。希望我們很快會從MongoDB中看到一個內置功能,但在此之前我必須使用它。

+0

原來我對於何時使用Map/Reduce存在嚴重的誤解。我不應該實時使用map/reduce!這非常緩慢。它應該作爲後臺工作來運行。 map/reduce的結果應該作爲一個集合存儲,並且該集合應該被查詢。我的錯! – Fadi

0

法迪,爲「保持嵌入文檔分開」 - 組應該沒有問題

function getServiceData(collection, criteria) { 

    var res=db[collection].group({ 
     cond: criteria, 
     initial: {vals:[],globalVar:0}, 
     reduce: function(doc, out) { 
      if (out.globalVar%2==0) 
       out.vals.push({doc.whatever.kind.and.depth); 
       out.globalVar++; 
     }, 
     finalize: function(out) { 
      if (vals.length==0) 
       out.vals='sorry, no data'; 
      return out.vals; 
     } 
    }); 

    return res[0]; 
}; 
2

在與聚合框架你現在能夠做到這一點的2.1版本處理這個問題:

1: db.test.aggregate(
2: {$match : {}}, 
3: {$unwind: "$services.TCP80.data"}, 
4: {$match: {"services.TCP80.data.ts": {$gte: 1308060720}}} 
5:); 

您可以使用第2行中的自定義條件來過濾父文檔。如果您不想過濾它們,請將第2行退出。