2013-07-03 49 views
2

我試圖創建一個管道,它將計算有多少文檔符合某些條件。我看不出在條件中使用正則表達式的任何方法。這裏是我的管道的簡化版本註釋:是否有一種解決方法,以允許在Mongodb聚合管道中使用正則表達式

db.Collection.aggregate([ 
    // Pipeline before the issue 
    {'$group': { 
     '_id': { 
      'field': '$my_field', // Included for completeness 
     }, 
     'first_count': {'$sum': {     // We're going to count the number 
      '$cond': [        // of documents that have 'foo' in 
       {'$eq: ['$field_foo', 'foo']}, 1, 0 // $field_foo. 
      ] 
     }},          

     'second_count': {'$sum': {      // Here, I want to count the 
      '$cond': [         // Number of documents where 
       {'$regex': ['$field_bar', regex]}, 1, 0 // the value of 'bar' matches 
      ]           // the regex 
     }},           
    }, 
    // Additional operations 
]) 

我知道的語法是錯誤的,但我希望這傳達了我想要做的事。有沒有辦法在$ cond操作中執行這個匹配?或者,也可以在流水線早些時候在某處進行匹配,並將結果存儲在文檔中,以便我只需在此處匹配布爾值。

回答

5

這個問題似乎來了很多次,沒有解決方案。 我知道有兩種可能的解決方案: 解決方案1-使用mapReduce。 mapReduce是讓用戶可以做任何可以想象和編程的聚合的一般形式。

以下是使用mapReduce的mongo shell解決方案 我們考慮以下'st'集合。

db.st.find()

{ "_id" : ObjectId("51d6d23b945770d6de5883f1"), "foo" : "foo1", "bar" : "bar1" } 
{ "_id" : ObjectId("51d6d249945770d6de5883f2"), "foo" : "foo2", "bar" : "bar2" } 
{ "_id" : ObjectId("51d6d25d945770d6de5883f3"), "foo" : "foo2", "bar" : "bar22" } 
{ "_id" : ObjectId("51d6d28b945770d6de5883f4"), "foo" : "foo2", "bar" : "bar3" } 
{ "_id" : ObjectId("51d6daf6945770d6de5883f5"), "foo" : "foo3", "bar" : "bar3" } 
{ "_id" : ObjectId("51d6db03945770d6de5883f6"), "foo" : "foo4", "bar" : "bar24" } 

我們想按FOO,並且對於每個FOO,計數文檔的數量,以及文檔的與棒包含數子串「bar2'.that是:

foo1: nbdoc=1, n_match = 0 
foo2: nbdoc=3, n_match = 2 
foo3: nbdoc=1, n_match = 0 
foo4: nbdoc=1, n_match = 1 

爲了做到這一點,定義下列地圖功能

var mapFunction = function() { 
    var key = this.foo; 
    var nb_match_bar2 = 0; 
    if(this.bar.match(/bar2/g)){ 
    nb_match_bar2 = 1; 
    } 
    var value = { 
    count: 1, 
    nb_match: nb_match_bar2 
    }; 

    emit(key, value); 
}; 

及以下減少功能

var reduceFunction = function(key, values) { 

    var reducedObject = { 
    count: 0, 
    nb_match:0 
    }; 
    values.forEach(function(value) { 
    reducedObject.count += value.count; 
    reducedObject.nb_match += value.nb_match; 
    } 
); 
    return reducedObject; 
}; 

運行mapduce並將結果存儲在收集map_reduce_result

db.st.mapReduce(mapFunction, reduceFunction, {out:'map_reduce_result'}) 
{ 
    "result" : "map_reduce_result", 
    "timeMillis" : 7, 
    "counts" : { 
    "input" : 6, 
    "emit" : 6, 
    "reduce" : 1, 
    "output" : 4 
}, 
"ok" : 1, 
} 

最後,我們可以查詢集合map_reduce_result,瞧!使用兩個單獨的聚合和合並 解決

> db.map_reduce_result.find() 
{ "_id" : "foo1", "value" : { "count" : 1, "nb_match" : 0 } } 
{ "_id" : "foo2", "value" : { "count" : 3, "nb_match" : 2 } } 
{ "_id" : "foo3", "value" : { "count" : 1, "nb_match" : 0 } } 
{ "_id" : "foo4", "value" : { "count" : 1, "nb_match" : 1 } } 

的2-我不會透露具體細節該解決方案爲任何蒙戈用戶可以很容易地做到這一點。 第1步:做聚合,忽略需要正則表達式求和的部分。 第二步:在第一步的同一個密鑰上進行第二次聚合分組。 管道的第一階段:匹配正則表達式; 階段2:與第一步相同的鍵上的組,計算每個組中的doc數{$ sum:1}; 步驟3:合併步驟1和2的結果:對於出現在兩個結果中的每個鍵添加新字段,如果鍵不存在,則在第二結果中將新鍵設置爲0。

Voila!另一種方案

相關問題