Tengo una base de datos con la siguiente estructura:

Ahora se pueden calificar dos pinturas entre sí y luego se actualiza la calificación. Pero puede suceder que una pintura se califique varias veces al mismo tiempo. Por lo tanto, intenté usar una transacción anidada (ver más abajo) para evitar condiciones de carrera:
function pictureClicked(picture) { const db = getDatabase(); const leftRef = ref(db, '/paintings/' + generateDbName(currentLeft)); const rightRef = ref(db, '/paintings/' + generateDbName(currentRight)); const winnerLeft = (picture === 'left') ? 1 : 0; runTransaction(leftRef, (leftP) => { if (leftP) { runTransaction(rightRef, (rightP) => { if (rightP) { // Calculation of the new rating for each painting (Elo System) const tRatingLeft = Math.pow(10, leftP.rating / 400); const tRatingRight = Math.pow(10, rightP.rating / 400); const expectedLeft = tRatingLeft / (tRatingLeft + tRatingRight); const expectedRight = tRatingRight / (tRatingLeft + tRatingRight); // Setting new rating leftP.rating = leftP.rating + 32 * (winnerLeft - expectedLeft); rightP.rating = rightP.rating + 32 * ((1 - winnerLeft) - expectedRight); } return rightP; }); } return leftP; }); }Ahora bien, esta solución realmente no funciona y he leído que no es el mejor enfoque para este problema. La única solución que encontré fue ejecutar una transacción en la raíz de mi base de datos, pero me temo que esto conduciría a un cuello de botella y muchas de las transacciones iniciadas ni siquiera escribirían en la base de datos, ya que las transacciones solo se reintentan 25 veces (o ¿Mi miedo aquí es infundado?). ¿Existen otras soluciones a este problema?
Las transacciones de Firebase Realtime Database se ejecutan en una sola ruta en su base de datos. Actualmente no hay forma de ejecutar una transacción en múltiples rutas, por lo que el enfoque común es ejecutar la transacción en la ruta compartida de nivel más bajo ( /paintings en su caso).
De hecho, esto puede dar lugar a más conflictos, ya que hay más usuarios que realizan transacciones simultáneas.
La única alternativa que he usado a veces es construir mi propio mecanismo de transacción usando:
Esto es bastante no trivial incluso para casos simples y puede requerir cambiar su estructura de datos y/o agregar valores adicionales a cada solicitud. Pero si supera esos obstáculos, le permitirá ejecutar una "transacción" a través de múltiples rutas.