我们知道Firebase没有计数查询,拥有计数器的方法是两个,在客户端获取所有数据或在数据库中存储计数值。我使用第二种方法,因为第一种方法仅在数据很少时才有效。
这个方法的问题是我可以有很多并发编写器,我用我的方法解决了这个问题,如果没有存储数据,它会尝试用递增或递减的计数器重新保存数据。
好的,当我想只更改一个计数器时,此方法运行良好,但在不同的情况下,我想用一个事务更改许多不同的计数器,在这种模式下,存在一种风险,即在不同的尝试后数据无法保存,因为我们可以在许多不同的节点中拥有许多并发编写器。具有原子更新的数据结构示例如下:
如果我保存
"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
可见,在批量更新的情况下,我必须更新许多可以拥有大量并发写入器的计数器,在这种情况下,很容易就能够在不同的时候更新所有计数器重试。
另一种情况是这个
"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 :(得分:0)
您正在寻找transactions,不是吗?
处理可能被并发损坏的数据时 修改,如增量计数器,您可以使用事务 操作。您可以为此操作提供更新功能和 可选的完成回调。更新功能接受当前 作为参数的数据状态,并返回新的所需状态 想写。如果另一个客户端之前写入该位置 成功编写新值后,将调用更新函数 再次使用新的当前值,并重试写入。
docs中的示例:
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;
});
}
作为补充,您只能删除已删除用户发布的内容,因此计数器将保持相同的值,而不是评论/帖子将有&#34;帖子被删除&#34;