2011-04-25 20 views
0

我有一個包含一系列事件的couchdb。每個事件都有一個所有者,一個ID,一個它發生的時間和一條消息(加上一堆其他東西,這對本次練習無關緊要)。我想要列出最近發生的事件。我翻看了這個問題CouchDB - filter latest log per logged instance from a list,並嘗試使用它與減速器中的比較翻轉以保留第一條消息(使用具有複雜鍵的表單)。Couchdb map/reduce返回流中的第一個,然後按時間排序

不幸的是,它似乎不太想做什麼。

這是我的地圖功能

function(doc) { 
    var owner, id; 
    if (doc.owner 
     && doc.stream_id 
     && doc.message 
     && doc.receipt_time) 
    { 
     emit([doc.owner,doc.stream_id,doc.receipt_time], 
      { owner: doc.owner, 
      stream_id: doc.stream_id, 
      timestamp: doc.receipt_time, 
      message: doc.message 
      }); 
    } 
} 

和我的降低功能

function(keys, values) { 
    var challenger, winner = null; 
    for (var a = 0; a < values.length; a++) { 
     challenger = values[a]; 
     if (! winner) { 
     winner = challenger; 
     } else { 
     if (winner.owner !== challenger.owner 
      && winner.trace_id !== challenger.trace_id) { 
      return null; 
     } else if (challenger.timestamp < winner.timestamp) { 
      winner = challenger; 
     } 
     } 
    } 
    return winner; 
} 

然後我用?降調用=真&組=真& group_level = 2來得到每個流的第一條消息但是,它似乎不是按時間排序的,而是由owner和stream_id這樣的

{"rows":[ 
    {"key":["sam","a"], 
    "value": 
    {"owner":"sam","stream_id":"a","timestamp":1303754236482,"message":"foo"} 
    }, 
    {"key":["sam","b"], 
    "value": 
    {"owner":"sam","stream_id":"b","timestamp":1303752578476,"message":"bar"} 
    }, 
    {"key":["jim","j1"], 
    "value": 
    {"owner":"jim","stream_id":"j1","timestamp":1303625378839,"message":"stuff"} 
    }, 
    {"key":["bob","loblaw"], 
    "value": 
    {"owner":"bob","stream_id":"loblaw","timestamp":1303328396532,"message":"more stuff"} 
    }, 
    {"key":["anthony","foo"], 
    "value": 
    {"owner":"anthony","stream_id":"foo","timestamp":1303769699444,"message":"even more"} 
    } 
]} 

(注意,最終條目實際上是最近的時間)。

所以我想要的是最後的觀點是現在它是按時間排序的。有沒有辦法做到這一點?

回答

0

如果我正確地理解了你,你並不想過濾事件的集合,而只是命令它們。假設這是正確的,該解決方案實際上非常簡單,您甚至不需要減少功能。映射函數中發出的鍵用於對視圖進行排序,首先按鍵中的第一個鍵,然後通過它的其餘部分進行處理。換句話說,如果你想通過把stream_id然後receipt_time進行排序,你的電話發出應該是這樣的:

emit([doc.stream_id,doc.receipt_time,doc.owner], doc.message); 

當然,如果你不是想receipt_time進行排序,然後把stream_id,將鍵改爲[doc.receipt_time,doc.stream_id,doc.owner]。我不認爲有必要在鑰匙中已經存在的價值中包含任何東西,這就是爲什麼我將價值降低到僅僅是消息。

+0

我想你是誤會。對於任何一個所有者+ stream_id,可以有多達幾千條消息。我想在每個流中顯示第一條消息,然後按時間戳排序。如果你命令它們[owner,stream_id,receipt_time],然後通過group_level 2和我概述的reduce函數,我得到每個流的所有者和stream_id的第一條消息,但是**它們按時間排序。如果我包含receipt_time(即,group_level 3),我會收到每條消息,以便達到目的。 – Nym 2011-04-26 03:52:36

+0

你說得對,我誤解了。我認爲可能還有更簡單的方法可以實現,但我必須考慮這一點。也許其中一位Couch專家會出現並在此期間提供答案。 – 2011-04-26 15:50:37

0

嗯,我認爲最簡單的就是避免這個問題。

由於我控制發送事件的軟件,我只在流中的第一個文檔中添加了"start":true,字段,所以view函數只是發出具有該值的事件。

這意味着我不能得到這個歷史數據,但沒關係,因爲這主要是爲了檢查最近的流。

我試過的另一種方法是添加一個列表函數,它在每個擁有者stream_id的第一個實例上發送一個視圖,該視圖的關鍵字是[timestamp,owner,stream_id],但是,當你限制它時,會遇到問題不限制最終渲染列表,而是限制原始視圖,所以額外的密鑰到目前爲止效果最好)。

我仍然想知道是否有辦法用原始數據做到這一點。

1

將stream_created_at時間戳存儲在每條消息中。因此,對於第一條消息,你需要花時間。對於流中的每一條下一條消息,都從前一條消息中複製(創建一個視圖以獲取stream_created_at_by_stream_id)。

然後創建視圖,其發射:

[doc.owner,doc.stream_created_at, doc.stream_id, doc.receipt_time] 

這將來自相同流的組消息一起同時維持時間排序。 stream.id將確保當兩個流同時被創建時來自不同流的消息不會混淆。而receipt_time會按時間順序排列流中的消息。

所以最終你會得到像Facebook一樣的談話。而且你根本不需要任何減少功能。

相關問題