我有一个Firebase数据库实例,我想为某个节点添加一个计数器。
每次用户执行特定操作时,我都想增加节点值。如何做到这一点而不会出现同步问题?如何使用Google函数来做到这一点?
例如:
database{
node {
counter : 0
}
}
在某些时间,3个不同的用户在计数器上读取该值,然后尝试增加它。由于它们在完全相同的时间读取,所以它们全部读取为“ 0”并递增为“ 1”,但是执行结束时所需的值应该为“ 3”,因为它被读取了3次。
=================更新=================
@renaud指出要使用事务来保持已保存数据的同步,但是我还有另一种情况,我还需要在读取端进行同步:
例如 用户读取了实际值,因此它会执行不同的操作,并通过增加一个值来完成...
在像enviorement这样的sql中,我会编写一个执行该操作的过程,因为无论用户如何处理信息,我总是通过增加一个来完成
如果我确实理解@renaud回答正确,那么在这种情况下,4个同时读取数据库的不同用户将获得0作为当前值,然后在事务更新时最终存储的值将为4,但是在客户端,每个人只是读0
答案 0 :(得分:2)
在这种情况下,您必须使用事务,请参见https://firebase.google.com/docs/database/web/read-and-write#save_data_as_transactions和https://firebase.google.com/docs/reference/js/firebase.database.Reference#transaction
交易将“确保与其他同时写入同一位置的客户端没有冲突。”
在Cloud Function中,您可以按照以下方式编写代码,例如:
....
const counterRef = admin
.database()
.ref('/node/counter');
return counterRef
.transaction(current_value => {
return (current_value || 0) + 1;
})
.then(counterValue => {
if (counterValue.committed) {
//For example update another node in the database
const updates = {};
updates['/nbrOfActionsExecuted'] = counterValue.snapshot.val();
return admin
.database()
.ref()
.update(updates);
}
})
或者如果您只想更新计数器,则只需执行以下操作(由于事务返回了Promise,如上面提到的第二个链接中所述):
exports.testTransaction = functions.database.ref('/path').onWrite((change, context) => {
const counterRef = admin
.database()
.ref('/node/counter');
return counterRef
.transaction(current_value => {
return (current_value || 0) + 1;
});
});
请注意,在第二种情况下,我以Realtime Database触发器作为触发器的示例。