2017-05-16 52 views
1

前過濾鍵我有具有以下格式文檔的CouchDB數據庫:CouchDB的視圖 - 分組

{ createdBy: 'userId', at: 123456, type: 'action_type' } 

我想寫一個觀點,這將使我如何每種類型的行爲是由創建用戶。我能做到這一點,這是否創建一個視圖:

emit([doc.createdBy, doc.type, doc.at], 1); 

通過減少功能「和」和消費這樣的觀點:

/_design/userActionsDoc/_view/userActions group_level = 2

這個返回結果與行剛剛在我想要的方式:

"rows":[ {"key":["userId","ACTION_1"],"value":20}, ... 

的問題是,現在我要篩選特定時間段的結果。所以我想要獲得完全相同的信息,但只考慮在特定時間段內發生的行爲。

我可以「在」如果我發射的字段以不同的順序過濾由文檔。

?group_level = 3 & startkey = [149328316160] & endkey = [1493283161647,{},{}]

emit([doc.at, doc.type, doc.createdBy], 1); 

但我不會得到由用戶id和操作類型分組的結果。有沒有辦法兼得?也許寫我自己的減少功能?

回答

1

我覺得你的痛苦。過去我做了兩件不同的事情來試圖解決類似的問題。

第一個模式是一種痛苦,可能工作的重大或可能不會在所有工作。我經歷過兩次。你的地圖功能看起來是這樣的:

function(doc) { 
    var obj = {}; 
    obj[doc.createdBy] = {}; 
    obj[doc.createdBy][doc.type] = 1; 

    emit(doc.at, obj); 
    // Ignore this for now 
    // emit(doc.at, JSON.stringify(obj)); 
} 

然後你減少功能如下:

function(key, values, rereduce) { 
    var output = {}; 
    values.forEach(function(v) { 
    // Ignore this for now 
    // v = JSON.parse(v); 
    for (var user in v) { 
     for (var action in v[user]) { 
     output[user][action] = (output[user][action] || 0) + v[user][action]; 
     } 
    } 
    }); 
    return output; 
    // Ignore this for now 
    // return JSON.stringify(output); 
} 

對於大型數據集,這通常會導致一個沙發上的錯誤,說明你的減少功能沒有快速萎縮足夠。在這種情況下,你可以到字符串化/解析爲在代碼中的「忽略」的評論顯示的對象。

這背後的原因是,CouchDB的最終希望你輸出一個簡單的物體,像在減少函數的字符串或整數。根據我的經驗,只要字符串保持不變,字符串變長似乎並不重要。如果您輸出的是對象,則在某些時候會出現函數錯誤,因爲您已經爲該對象添加了太多道具。


第二種模式可能更好,但要求您的時間段提前「定義」。如果您的時間段要求可以鎖定到特定的年份,特定的月份,日期,季度等,您只需在地圖功能中多次發送。下面我假設at屬性是毫秒爲單位,或至少一些日期構造能夠準確解析。

function(doc) { 
    var time_key; 
    var my_date = new Date(doc.at); 

    //// Used for filtering results in a given year 
    //// e.g. startkey=["2017"]&endkey=["2017",{}] 
    time_key = my_date.toISOString().substr(0,4); 
    emit([time_key, doc.createdBy, doc.type], 1); 

    //// Used for filtering results in a given month 
    //// e.g. startkey=["2017-01"]&endkey=["2017-01",{}] 
    time_key = my_date.toISOString().substr(0,7); 
    emit([time_key, doc.createdBy, doc.type], 1); 

    //// Used for filtering results in a given quarter 
    //// e.g. startkey=["2017Q1"]&endkey=["2017Q1",{}] 
    time_key = my_date.toISOString().substr(0,4) + 'Q' + Math.floor(my_date.getMonth()/3).toString(); 
    emit([time_key, doc.createdBy, doc.type], 1); 
} 

然後,您的縮小功能與您的原始功能相同。基本上,你只是試圖爲你的密鑰中的第一個項目定義一個與定義的時間段相對應的常量值。適用於商業報告,但不適合靈活的時間段。

+0

謝謝!我會嘗試的 –