2013-07-03 3 views
38

Firebase consente di aggiornare una risorsa transactionally. A quanto ho capito, il cliente fa questo acquisto inviando richieste al server dicendo "Se il vecchio valore è X, crea il nuovo valore Y". In caso di conflitto, il server può rifiutare più aggiornamenti del client fino a quando uno non viene accettato.Firebase: come aggiornare atomicamente più risorse?

Ora, cosa succede se voglio aggiornare più risorse atomicamente?

Cosa succede se il primo aggiornamento viene accettato e quindi il client viene disconnesso prima che venga accettato il secondo aggiornamento. C'è un modo per includere più aggiornamenti in una transazione atomica? In caso contrario, esiste una soluzione idiomatica a questo problema?

risposta

44

UPDATE

E 'ora possibile aggiornare più posizioni in modo atomico. Vedi this blog post per i dettagli.

var mergedUpdate = {}; 
mergedUpdate[ 'users/' + userId + '/widgets/' + widgetId ] = true; 
mergedUpdate[ 'widgets/' + widgetId ] = widgetData; 

var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/"); 
ref.update(mergedUpdate); 

Questo non impone dati delle transazioni (se il valore è attualmente X, rendono Y), ma questa parte può essere spostato security rules. Per esempio, se vogliamo aggiornare due contatori, allo stesso tempo, potremmo aggiungere dichiara:

{ 
    "counter1": { 
    ".validate": "newData.val() === (data.val()||0)+1" 
    }, 

    "counter2"1 { 
    ".validate": "newData.val() === (data.val()||0)+1" 
    } 
} 

Ora siamo in grado di tentare lo stesso aggiornamento multi-path come sopra. Se i valori sono cambiati dall'ultima volta che li abbiamo letti dal server, il tentativo fallirà. Possiamo controllare if(error.code === 'PERMISSION_DENIED') { ... } per vedere se l'errore è dovuto alla convalida e riprovare di conseguenza.

ORIGINALE POST

L'unico modo per farlo è quello di eseguire una transazione su un antenato comune.

Ad esempio, se si desidera aggiornare/a/b/c e/a/x/y, è possibile eseguire una transazione in/a e modificare entrambi i valori.

Lo svantaggio di questo approccio è che può essere costoso con I/O di rete, poiché tutti i dati all'interno della transazione devono essere scaricati e quindi inviati al server.

Un approccio più complicato ma potenzialmente più potente che si potrebbe prendere in considerazione è la ristrutturazione dei dati in modo che, anziché memorizzare i valori effettivi, si memorizzi una cronologia delle modifiche. Ad esempio, se si memorizzano informazioni sul saldo bancario, è possibile memorizzare una cronologia di depositi e prelievi. Poi, quando volevi ottenere il saldo, avresti riprodotto l'intera storia e calcolato il saldo finale.

La bellezza di questo approccio è che ti permette di fare aggiornamenti atomici. Ad esempio, se trasferisci denaro dall'accountA all'accountB, devi semplicemente aggiungere un elemento alla fine del log dicendo "trasferimento dall'account A all'accountB N dollars". L'aggiunta di quel singolo elemento è un'operazione atomica.

Questo è l'approccio che adottiamo con Firepad, il nostro editor di testo collaborativo.

+0

Grazie per la risposta. Concettualmente mi piace memorizzare nuove transazioni piuttosto che aggiornare sul posto, ma penso che sia praticabile da un punto di vista delle prestazioni solo se esiste una funzionalità di materializzazione delle query. La riproduzione di tutta la cronologia sarebbe lenta. –

+0

Non ce n'è uno (almeno non ancora), ma vediamo sicuramente come sarebbe utile! Per ora si può materializzarsi la query sul client e memorizzarlo di nuovo ad un "checkpoint" in Firebase (questo è come funziona Firepad), o si potrebbe avere un node.js o un server basato su Java in esecuzione da qualche parte come un client che si materializza Firebase è per te. –

+0

HI! Grazie, ma l'ho appena provato e ho ricevuto un errore: "Riga 10: L'operando a sinistra di || deve essere booleano." Mi sto perdendo qualcosa? Sto usando Firebase 3.0 ... –

0

c'è un altro modo .... molto noioso ... e non realmente le operazioni ...

Come Firebase permette atomicamente cambia un valore, è possibile creare una serratura o semaforo con il significato di "ha iniziato una transazione sulle risorse x, yez "...ovviamente, non è una transazione reale in quanto non blocca le risorse, una parte della serratura. Potremmo chiamarlo transazione per convenzione. I clienti devono sapere che quando il blocco è occupato, non dovrebbero cambiare le risorse x, yez ....

+2

si interrompe quando due client richiedono contemporaneamente il semaforo. non una vera serratura quindi non risolve il problema della concorrenza, riduce le possibilità. –