I have a path within firebase realtime database where I want to use incrementing keys for:
/foo/1 {a: "some data"}
/foo/2 {a: "some other data"}
Right now, I'm querying the last /foo/ record to get the last number, and setting /foo/3 as the latest object. However this is a race condition-- if two users try to do this at the same time, it could lead to them both creating /foo/3 (and one overwriting the other).
Is there any way I can do this safely? It looks like realtime database has some limitied support for transactions, but I'm not sure if they can be used for this use case.
Thanks in advance!
edit: Here is exactly what I'm doing currently
const fooCollection = await admin.database().ref("foo").limitToLast(1).get();
let lastFooId;
fooCollection.forEach(snapshot => {
lastFooId = snapshot.key
})
let newFooId = 0;
if(lastFooId) {
newFooId = parseInt(lastFooId) 1;
}
await admin.database().ref(`/foo/${newOrderId}`).set(fooData);
Is there a way I can make this a transaction on the /foo/ path?
CodePudding user response:
There is no way to perform a query inside a transaction in the Firebase Realtime Database.
The idiomatic way to do this is to keep a counter value at a known path (typically referred to as a sequence in other databases), instead of using a query to determine its value - and then use a transaction (or multi-path update) to write both the new value to that sequence/value and the new node.
This would also solve the inherent scalability problem that comes from querying an even-growing list. Even when that limit is at the hundreds of thousand (or nowadays more likely: millions) of nodes, it is still better to use an approach that doesn't have such a scalability limit.