2016-07-04 41 views
10

stavo indagando Database Firebase sample per Android e capito che memorizza i propri dati nel seguente modo:Firebase Database - la tecnica "a ventaglio"

enter image description here

io non sono abbastanza familiarità con NoSQL tecniche e cercando di capire perché dobbiamo perseguire ciascuna entità post due volte - a posts e user_posts corrispondentemente. La documentazione dice che questo approccio è chiamato "Fan Out" e sono pienamente d'accordo che potrebbe essere utile accedere ai post degli utenti tramite una semplice costruzione come databaseReference.child("user-posts").child("<user_uid>"). Ma perché abbiamo bisogno del nodo posts? E se avessimo bisogno di aggiornare qualche post? Dobbiamo farlo due volte?

// [START write_fan_out] 
private void writeNewPost(String userId, String username, String title, String body) { 
    // Create new post at /user-posts/$userid/$postid and at 
    // /posts/$postid simultaneously 
    String key = mDatabase.child("posts").push().getKey(); 
    Post post = new Post(userId, username, title, body); 
    Map<String, Object> postValues = post.toMap(); 

    Map<String, Object> childUpdates = new HashMap<>(); 
    childUpdates.put("/posts/" + key, postValues); 
    childUpdates.put("/user-posts/" + userId + "/" + key, postValues); 

    mDatabase.updateChildren(childUpdates); 
} 
// [END write_fan_out] 

Quindi mi chiedo ... quando questo approccio potrebbe essere utile e quando no? Firebase SDK fornisce strumenti per mantenere sincronizzati tutti i duplicati durante l'aggiornamento o la rimozione dei dati?


UPDATE: Ecco la spiegazione received dalla squadra Firebase:

la ragione per i messaggi sono duplicati è perché vogliamo essere in grado di ottenere rapidamente tutti i messaggi appartenenti a un utente (come hai suggerito) e il filtro dall'elenco di tutti i post di sempre per ottenere i post da un utente può diventare piuttosto costoso con l'espansione del numero di post.

Ciò significa che dobbiamo aggiornare il post in due posizioni ogni volta che lo aggiorniamo. Rende il codice un po 'più brutto, ma poiché le query sono più comuni delle scritture, è meglio ottimizzare per leggendo i dati.

ho il sospetto che questo approccio potrebbe apparire non proprio elegante, ma è probabilmente l'opzione più veloce per grandi insiemi di dati fino a quando si esegue selezionare più spesso di quanto UPDATE. Tuttavia, in alcuni casi preferisco attenermi ad altre soluzioni consigliate qui.

+1

Per una buona introduzione, vedere [Modellazione dati NoSQL] (https://highlyscalable.wordpress.com/2012/03/01/nosql-data-modeling-techniques/) –

+0

Nella pagina "Struttura del database" da i documenti, l'orientamento è usare le bandiere per indicare la relazione a due vie (come affermato in altri commenti), mentre ciò che stanno facendo in questo codice contraddice questo. Penso che dovrebbero aggiungere alcuni chiarimenti in merito nella documentazione, ho appena inviato un feedback su di esso nella pagina dei documenti di Firebase. –

risposta

6

dati Fan Out è una grande tecnica per gestire enormi quantità di dati. Se non utilizzi questo modello, potresti avere seri problemi di ridimensionamento in futuro.

Quello che vedo dalla struttura del database, è che si stanno memorizzando le informazioni di intero due volte, e che non è una buona pratica. Si desidera memorizzare solo un riferimento al post in un altro nodo. Quindi, avrai un nodo chiamato users-posts che consisterà di chiavi utente, e ognuna di quelle chiavi avrà una serie di chiavi post con valore di true.Per rendere più chiaro:

enter image description here

In questo modo, si sta inseguimento che i messaggi che l'utente ha scritto sotto il nodo users-posts; e anche l'utente che ha scritto ciascun post sotto il nodo posts. Ora potrebbe essere necessario ottenere un elenco di tutti i post degli utenti. Quello che dovresti fare è sincronizzare sul nodo users-posts/USER_KEY/ su ottenere le chiavi per tutti i messaggi che l'utente ha scritto, e poi ottenere più informazioni sul post usando la chiave del messaggio che hai appena ricevuto.

Perché si consiglia questa progettazione del database? Perché sei ottenendo molte meno informazioni per ogni sincronizzazione (con Firebase non stiamo emettendo richieste per sé, quindi chiamo la lettura di una sincronizzazione). Nel tuo esempio, se colleghi un listener allo user-posts/USER_KEY/ per ottenere un elenco di tutti i post, chiederai anche ALL le informazioni di OGNI E OGNI post che hanno scritto. Con l'approccio "data fan out" puoi solo chiedere le informazioni sul post di cui hai bisogno perché hai già la chiave dei post.

+1

Grazie per la risposta dettagliata. L'approccio che hai suggerito sembra ragionevole per me. Tuttavia, il team di Firebase ha deciso di duplicare l'intera entità 'post' nel loro campione e hanno anche fornito alcune spiegazioni su questo, vedi la mia modifica. – fraggjkee

+1

erm, stavo usando l'approccio basato su indice chiave in precedenza fino a quando ho letto questo post da Firebase. Duplicano tutti i dati, anche il nome utente e in realtà preferisco i dati duplicati perché ho trovato query di ricerca e fusione di oggetti sono stanchi. https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjEgaPc55vQAhXBUrwKHddBBLoQFggaMAA&url=http%3A%2F%2Ffirebase.googleblog.com%2F2015%2F10%2Fclient -side-fan-out-for-data-consistency_73.html & usg = AFQjCNFd2jOX7mx60HqPbnVcQSvYRoDEnA & sig2 = zg1IYXT5gy7VPqUI6NNMkQ & bvm = bv.138169073, d.c2I – vzhen

+0

Ciò che suggerisci è un po 'il contrario del fan-out. Questo approccio suggerito semplifica il salvataggio dei dati, ma rallenta la query mentre ci sono milioni di post ed è necessario interrogarli per id uno per uno. Quindi fan-out (duplicazione) è ciò che Firebase ha suggerito per gestire questo tipo di scala, vedere questo post: https://firebase.googleblog.com/search?updated-max=2015-10-13T20:08:00-07 : 00 & max-results = 1 & start = 24 & per data = false –

2

Secondo me questo non è un buon approccio dal momento che è necessario mantenere i dati sincronizzati e Firebase non fornisce alcuno strumento per mantenere i duplicati sincronizzati. Un buon approccio sarebbe quello di memorizzare solo la chiave in user-posts.

vi suggerisco di leggere questo, è molto interessante per capire come strutturare i dati: https://www.firebase.com/docs/web/guide/structuring-data.html

+2

La semplice conservazione delle chiavi è un approccio, la duplicazione dell'intero post è un'altra. Qual è il migliore, dipende dal tuo scenario e dalla volontà di avere dati duplicati rispetto a caricare i dati in due passaggi. Potresti scrivere regole di sicurezza per mantenere i dati sincronizzati, se lo desideri. –

+0

Grazie a @FrankvanPuffelen. Intendi dire che esiste un modo per mantenere i dati sincronizzati usando solo le regole di sicurezza? O che posso scrivere le mie regole di sicurezza per mantenere la consistenza dei miei dati duplicati quando spingo? Grazie in anticipo –

+3

https://firebase.googleblog.com/search?updated-max=2015-10-13T20:08:00-07:00&max-results=1&start=24&by-date=false - questo articolo descrive alcuni Firebase -le cose specifiche semplificano tutto ciò che riguarda l'approccio Fan Out a quanto pare (aggiornamenti multi-path e fan-out lato client). – fraggjkee