2013-01-04 32 views
2

這裏有一堆關於使用CouchDB分頁的問題,但沒有一個完全符合我想知道的內容。使用可變鍵的CouchDB分頁

基本上,我有一個按票數排序的結果集,而且我想按降序瀏覽整個集合。

以下是map供參考。

function(doc) { 
    emit(doc.votes); 
} 

現在,問題所在。我發現startkey_docid不適用於它自己。您必須將其與startkey結合使用。問題是,對於查詢,我不使用startkey參數(我不想限制結果,只是得到最多 - >至少)。我想我可以使用startkey = {{doc.votes}} & startkey_docid = {{doc._id}}來代替,但是在某人點擊「下一頁」鏈接時,文檔的投票數可能已經改變。

解決這個問題的方法似乎很明顯:只需設置startkey=99999999,以便它將返回數據庫中的所有文檔,並且我可以使用startkey_docid從我們上次停止的那個開始。奇怪的是,當我這樣做時,startkey_docid停止工作,並只允許所有結果再次返回。顯然startkey需要完全等於在startkey_docid中使用_id的文檔上的密鑰。

我在問的是,是否有人知道使用startkey_docid來解決實際startkey在您想使用它時可能發生變化的解決方法?我的應用程序是否應該通過_id查找文檔,並立即使用doc.votes值,希望它在請求之間的幾毫秒內沒有改變?即使這似乎不是很可靠。

編輯:結束切換到Mongo的速度,所以這個問題原來是有點沒有意義。

回答

1

我從來沒有做過這樣的事情,但我想我有一些想法如何做到這一點。你可以做的是拍攝收視率的快照,並在每一頁中提及。您可能希望自己的視圖不要消耗太多空間,因此在拍攝快照後,您不應該將單獨的文檔副本映射爲未更改的投票。因此,您可以執行以下操作:

  1. 將一些評分歷史記錄添加到文檔的時間戳中。
  2. 將評分和歷史記錄映射到此地圖。
  3. 在您的應用程序中獲取當前時間:start_time = Date.now()並查詢所有頁面。
  4. 清理歷史最早,最舊的活動會話。

問題是,如果您發出[votes, date]並嘗試分頁,則永遠不會知道您必須提取多少個文檔以獲取每頁所需的數字。總會有一些舊的版本,你必須跳過,然後你將從數據庫中獲得下一個版本。這就是爲什麼你可以考慮發射:[date, votes],閱讀視圖總是兩次 - 對於start_time和當前時間,併合並和排序結果(如合併排序)。

Ad。1:

{ ..., 
    votes: 12, 
    history: [ 
    {date: 1357390271342, votes: 10}, 
    {date: 1357390294682, votes: 11} 
    ] 
} 

Ad.2:

function (doc) { 
    emit([{}, doc.votes], null); 
    doc.history && doc.history.forEach(function(h) { 
    emit([h.date, h.votes], null); 
    }); 
} 

Ad.3:

?startkey=[start_time, votes]&limit=items_per_page_plus1 
?startkey=[{}, votes]&limit=items_per_page_plus1 

合併列表,排序在您的應用程序votes(在列表中的功能)。 如果您在使用start_docid時遇到問題,那麼您可以發出[date, votes, id]並明確地使用ID進行查詢。即使這個特定的文檔改變了其votes它仍然可以在歷史中獲得。

Ad.4: 如果您發出[date, votes]那麼你可以得到過時的歷史寬度:?startkey=[0]&endkey=[oldest_active_session_time]&inclusive_end=falseupdate handler更新它們:

function(doc, req) { 
    if (!doc || !doc.history) return [null, 'Error']; 
    var history = new Array(); 
    var oldest = +(req.query.date); 
    doc.history.forEach(function(h) { 
    if (h.date >= oldest) 
     history.push(h); 
    }); 
    doc.history = history; 
    return [doc, 'OK']; 
} 

注:我沒有測試過,所以預計不會運行時沒有修改:)

據我所知,CouchDB使用b-tree陰影進行更新,原則上應該可以訪問較早版本的視圖。我沒有進入CouchDB設計,所以這只是一個猜測,似乎沒有任何(記錄)的API。

+0

其實我不確定你的回答是否正確,但是你做得很好,應該注意。 – Ph0en1x

0

我不能現在找出任何簡單的解決方案,但也有選擇:

  • 複製不那麼頻繁的排序列表,小型專用DB所以它會比更陳腐stale = ok
  • 以一種可以用一些更穩定的數據排序的方式修改您的模式。看看CouchDb指南中的銀行/帳簿示例:http://guide.couchdb.org/draft/recipes.html#banking。嘗試記錄每個投票並每小時減少一次。作爲獎勵,你會得到一個歷史/趨勢:)
0

我有點詫異這個問題一直沒有答案,因爲CouchDB的被褥的功能基本上做到這一點,當你通過地圖的結果分頁功能。我打開firebug來查看javascript控制檯中發生了什麼,因爲我分頁並看到每一組分頁結果都會將startkey和startkey_docid一起傳遞。因此,儘管問題是如何在不包含startkey的情況下進行分頁,CouchDB會指定startkey是必需的,並說明它如何工作。未指定endkey,因此如果指定的startkey只有一個結果,則下一組分頁結果還將包含與startkey不匹配的排序結果的下一個鍵。

所以爲了澄清一下,這個問題的答案是,在分頁並跟蹤startkey_docid時,還需要捕獲同一個文檔的startkey,它將成爲下一組結果的開始。當您調用分頁結果時,請使用捕獲的startkey和startkey_docid作爲couchdb的要求。關閉endkey,以便結果繼續到排序結果的下一個鍵。

希望能夠分頁但不指定鍵的用例場景有點奇怪。因此,假設下一個分頁結果的開始文檔確實將其關鍵值從9急劇變爲3.我們還假定地圖結果中只存在一個docid實例,即使它可能有潛在的潛力出現多次(我相信這是爲什麼startkey需要指定)。當用戶點擊下一個按鈕時,用戶的分頁結果現在已經從查看等級9移至等級3.但是如果除了startkey_docid之外還包括startkey,則分頁結果將剛剛開始從頭開始的排名9的結果,這是一個更合乎邏輯的進展,而不是潛在跳過一大組結果。