2016-11-09 24 views
4

我們知道,火力地堡沒有一個計數查詢,有一個計數器的方法有兩種,得到所有數據在客戶端或存儲在數據庫中的計數值。我使用第二種方法,因爲第一種方法只有在數據很少時纔有效。火力地堡計數器,增量更新的情況下

這種方法的問題是,我可以有很多併發的作家,我用我的方法解決了這個問題,如果數據未被存儲,它會嘗試用增加或減少的計數器來重新保存數據。

確定當我只想更改一個計數器時,此方法運行良好,但在不同的情況下,我想用一個事務更改許多不同的計數器,並且在此模式下存在一種風險,即經過不同的嘗試後數據無法保存,因爲我們可以在許多不同的節點中擁有許多併發寫入器。與原子更新數據結構的一個例子是如下:

如果我保存這個

"comment": { 
    "counter": {}, 
    "Data": { 
     "$Comment":{} 
    } 
} 


comment/counter = val + 1 
comment/Data/comment1 = data 

它的工作原理,如果我不更新,因爲其他作家正在更新計數器就在我可以用一個新的重試計數器的值,通常第一次後,我得出結論:成功的操作,但舉例來說,如果我想刪除一個用戶,他的一切行動,我想存儲這種類型的數據

"comment":{ 
    "counter":{}, 
    "Data": { 
    "$Comment":{} 
    } 
}, 

"$user": { 
    "follower":{ 
    "counter":{}, 
    "data":{ 
     "$Follower": {} 
    } 
    } 
} 
comment/counter = val - 1 
comment/Data/comment2 = null 
user1/follower/counter = val - 1 
user1/follower/data/user30 = null 
user2/follower/counter = val - 1 
user2/follower/data/user30 = null 
user3/follower/counter = val - 1 
user3/follower/data/user30 = null 

是可見的,在大批量更新的情況下,我必須更新很多計數器t可以有很多併發編寫器,在這種情況下,很容易在不同的重試之後無法更新所有計數器。

另一種情況是這樣的

"photo":{ 
    "$photo":{ 
    "comment":{ 
     "counter":{}, 
     "Data": { 
     "$Comment":{} 
     } 
    } 
} 

photo/10/comment/counter = val - 1 
photo/10/comment/Data/comment1 = null 
photo/10/comment/counter = val - 1 
photo/10/comment/Data/comment2 = null 
photo/10/comment/counter = val - 1 
photo/10/comment/Data/comment3 = null 

在這種情況下,這是不可能的,因爲我嘗試刪除具有相同的計數器不同意見,可以是僅值+ 1或價值相等更新計數器 - 1 。如果我想刪除所有的用戶數據,他可能會在同一張照片上寫下一些評論,但是我不能刪除一個交易中的所有評論,因爲只有單筆交易才能更新計數器。

我看到很多這樣的併發症,只是因爲不存在存在於任何類型的數據庫(SQL或NoSQL的)的計數查詢。我不懂爲什麼。這涉及到很多問題,否則無解浪費時間

下面是我的javascript函數來更新計數器。它如果不能在該記得自己是一個遞歸函數,因爲其他的更新併發作家

this.singleUpdate = function (paths, increment, countPath, retryCounter, callback) { 
      firebase.database().ref(countPath).once('value', function (counter) { 
       var value = counter.val() ? counter.val().value : 0; 
       var countValue = increment ? value + 1 : value - 1; 
       paths[countPath] = { value: null };     

       if (!increment && countValue == 0) { paths[countPath] = null; } 
       else { 
        paths[countPath].value = countValue;      
       } 

       firebase.database().ref().update(paths, function (error) { 
        if (error) { 
         retryCounter++; 
         if (retryCounter < 3) { singleUpdate(paths, increment, countPath, retryCounter, callback); } 
         else { callback(false, error); } 
        } else { 
         return callback(true, countValue); 
        } 
       }); 
      }); 
     } 
+0

這是一個問題?如果是這樣,您是否可以提供演示此問題的代碼示例以及Firebase結構的片段(如文本請勿插入圖片),以便我們瞭解您的數據? – Jay

+0

我發佈我的函數來更新計數器,但問題不在於客戶端代碼,而是在Firebase數據結構中,如果我想更新一些不同的計數器,可能我因爲更多計數器意味着更多可能的併發編寫者而導致我的事務失敗。但在firebase不存在一個計數查詢這是唯一的方法可能我認爲 – DThink

回答

0

您正在尋找transactions,不是嗎?

當與可能併發 修改,如增量計數器被損壞的數據時,您可以使用事務 操作。你可以給這個操作一個更新函數和一個可選的完成回調函數。更新函數將當前的 狀態的數據作爲參數,並返回您想要寫入的新的期望狀態。如果另一個客戶端在 之前寫入了該位置,則您的新值成功寫入,則您的更新函數將與新的當前值一起再次被調用 ,並重新嘗試寫入。從文檔

例子:

function toggleStar(postRef, uid) { 
    postRef.transaction(function(post) { 
    if (post) { 
     if (post.stars && post.stars[uid]) { 
     post.starCount--; 
     post.stars[uid] = null; 
     } else { 
     post.starCount++; 
     if (!post.stars) { 
      post.stars = {}; 
     } 
     post.stars[uid] = true; 
     } 
    } 
    return post; 
    }); 
} 

作爲補充,只能刪除發佈的刪除用戶的內容,因此計數器將繼續留在相同的值,而不是評論/後會出現「後是刪除「

+0

是的,我知道交易。另一件事是,我想更新更多的計數器只有一個查詢,在這種情況下,我不能使用事務,但更新方法。問題是,我認爲所有的客戶端方法都需要增加和減少在服務器端工作的方法。否則很多用戶很容易在不同時間寫作失敗。 – DThink

+0

@DThink你有單獨的應用服務器嗎?我可以爲你提供Go或Python中的例子來實現你想要的。但Firebase只有批量更新事務 –

+0

我使用nodejs腳本,但方法是相同的,事務或更新。但他沒有迴應我的需求:/ – DThink