2016-11-09 76 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