我有一个Firebase数据库实例,我想向某个节点添加一个计数器。
每次用户运行特定操作时,我都想增加节点值。如何在不出现同步问题的情况下做到这一点?如何使用谷歌函数来做到这一点?
前任。:
database{
node {
counter : 0
}
}
在特定时间,3 个不同的用户读取计数器上的值,并尝试递增它。由于它们同时读取,因此它们都读取"0"并增加到"1",但是执行结束时的所需值应该是"3",因为它被读取了 3 次
====================更新==
=====================@renaud指出使用事务来保持保存数据的同步,但我还有另一种情况,我也需要在读取端完成同步:
前任。 用户读取实际值,根据它执行不同的操作并通过递增一个来完成......
在像 enviorement 这样的 SQL 中,我会编写一个过程来执行此操作,因为无论用户如何处理信息,我都会通过递增一个来完成
如果我确实理解@renaud答案正确,在这种情况下,4 个不同的用户同时读取数据库将获得 0 作为当前值,然后在事务更新时,最终存储的值将是 4,但在客户端,他们每个人都只读取 0
在这种情况下,您必须使用事务,请参阅 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
事务将"确保与同时写入同一位置的其他客户端没有冲突"。
在云函数中,您可以按照以下行编写代码,例如:
....
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;
});
});
请注意,在第二种情况下,我使用了实时数据库触发器作为触发器的示例。