-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy path04s-publications-and-subscriptions.md.erb
217 lines (134 loc) · 12.3 KB
/
04s-publications-and-subscriptions.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
---
title: Pubblicazioni e Sottoscrizioni
slug: publications-and-subscriptions
date: 0004/01/02
number: 4.5
sidebar: true
contents: Come funzionano pubblicazioni e sottoscrizioni.|Cosa fa il pacchetto Autopublish|Alcuni schemi di pubblicazione.
paragraphs: 52
---
Pubblicazioni e sottoscrizioni sono uno dei fondamentali e più importanti concetti di Meteor, ma possono risultare complicati da capire all'inizio.
Questo ha portato a molte incomprensioni, come la convinzione che Meteor sia insicuro o che le applicazioni in Meteor non possono gestire grandi quantità di dati.
Buona parte dei motivi per cui le persone trovano questi concetti un po' confusi inizialmente è la "magia" che Meteor fa per noi. Sebbene questa magia sia molto utile, può oscurare ciò che sta succedendo realmente dietro le scene (come la magia tende a fare). Proviamo a togliere gli strati di magia per capire ciò che sta accadendo.
### I vecchi tempi
Guardiamo prima a ciò che accadeva nel 2011 quando Meteor non era ancora disponibile. Diciamo che state costruendo una semplice applicazione in Rails. Quando un utente raggiunge il vostro sito, il cliente (ad esempio il browser) manda una richiesta all'applicazione che risiede sul server.
Il primo lavoro dell'applicazione è quello di capire che dati l'utente vuole vedere. Potrebbe essere pagina 12 dei risultati di ricerca, le informazioni del profilo di Mary, i 20 ultimi tweet di Bob e così via. Potete figurarla come un commesso di una libreria che cerca negli scaffali il libro che avete richiesto.
Quando i dati corretti sono stati selezionati, il secondo lavoro dell'applicazione è quello di tradurre i dati in formato HTML leggibile da una persona (o JSON nel caso di un API).
Nella metafora della libreria, sarebbe il passaggio di impacchettare il libro che avete appena comprato e metterlo in una bella borsa. Questa è la parte "View" del famoso schema Model-View-Controller.
Infine, l'applicazione prende il codice HTML e lo restituisce al browser. Il lavoro è finito e ora che tutto è stato consegnato l'applicazione può rilassarsi con una birra e aspettare per la prossima richiesta.
### Come funziona Meteor
Rivediamo cosa rende Meteor così speciale. Come abbiamo visto, l'innovazione di Meteor sta nel fatto che se un'applicazione Rails vive solo **sul server**, un'applicazione Meteor comprende anche una componente che risiede **nel client** (il browser).
<%= diagram "client-server", "Pushing a subset of the database to the client.", "pull-right" %>
Questo è come un commesso che non solo trova il giusto libro per voi, ma vi segue fino a casa per leggerlo di notte (che ammettiamo suona un po' spaventoso).
Questa architettura fa in modo che Meteor faccia molte cose interessanti, prima fra tutte quello che Meteor chiama [database ovunque](http://docs.meteor.com/#sevenprinciples). In parole semplici, Meteor prende una parte del database e lo *copia nel client*.
Ci sono due grandi implicazioni: primo, invece di mandare il codice HTML al client, un'applicazione Meteor invia **i dati grezzi** e lascia che sia il client ad occuparsene ([dati sul filo](http://docs.meteor.com/#sevenprinciples)). In secondo luogo, si è in grado di **accedere ai dati istantaneamente** senza dover aspettare un intero giro di scambio con il server ([compensazione di latenza](http://docs.meteor.com/#sevenprinciples)).
### Pubblicare
Il database di un'applicazione può contenere decine di migliaia di documenti, alcuni dei quali possono essere dati privati o sensibili. Per questo motivo non dobbiamo ovviamente replicare tutto il database nel client, per ragioni di sicurezza e scalabilità.
Abbiamo bisogno di un modo per dire a Meteor quale **sottoinsieme** di dati può essere inviato al client e lo faremo attraverso una **pubblicazione**.
Torniamo a Microscope. Qui abbiamo tutti i post che si trovano nel database dell'applicazione:
<%= diagram "collections-1", "Tutti i posts contenuti nel database.", "pull-center" %>
Immaginiamo che alcuni dei nostri post siano stati segnalati per linguaggio inappropriato, anche se questa opzione non esiste al momento in Microscope. Anche se vogliamo tenere questi post nel database, non devono essere resi disponibili agli utenti (ad esempio inviati al client).
Il nostro primo compito è di dire a Meteor quali dati *vogliamo* mandare al client. Diciamo a Meteor che vogliamo **pubblicare** solo i post non segnalati:
<%= diagram "collections-2", "Esclusione dei posts segnalati.", "pull-center" %>
Questo è il codice corrispondente, che risiede sul server:
~~~js
// on the server
Meteor.publish('posts', function() {
return Posts.find({flagged: false});
});
~~~
Questo assicura che non ci sia **nessun modo possibile** che un client possa accedere ai post segnalati. In questo modo si rende sicura l'applicazione Meteor: dovete assicurarvi che state pubblicando solo i dati a cui volete che il client acceda.
<% note do %>
### DDP
Fondamentalmente potete pensare a pubblicazione/sottoscrizione come ad un tubo che trasferisce i dati da una collezione sul server (sorgente) ad una collezione lato client (obiettivo).
Il protocollo che gestisce questo comunicazione è chiamato **DDP** (che sta per Distributed Data Protocol). Per saperne di più sul DPP potete guardare [questo intervento alla Real-time Conference](http://2012.realtimeconf.com/video/matt-debergalis) di Matt DeBergalis (uno dei fondatori di Meteor), o [questo screencast](http://www.eventedmind.com/posts/meteor-subscriptions-and-ddp) di Chris Mather che vi mostra qualche dettaglio in più su questo concetto.
<% end %>
### Sottoscrizioni
Anche se vogliamo che gli utenti vedano tutti i post non segnalati, non possiamo inviare migliaia di post alla volta. Abbiamo bisogno di un modo con cui i client possano specificare di quale sottoinsieme di dati hanno bisogno e lo facciamo attraverso le **sottoscrizioni**.
Ogni dato a cui si fa una sottoscrizione viene **replicato** sul client grazie a Minimongo, l'implementazione lato client, contenuto in Meteor, di MongoDB.
Ad esempio, stiamo navigando sul profilo di Bob Smith e vogliamo mostrare solo i *suoi* post.
<%= diagram "collections-3", "Sottoscrivendosi ai posts di Bob, questi verranno replicati sul client.", "pull-center" %>
Come prima cosa sistemiamo le nostre pubblicazioni in modo che accettino un parametro:
~~~js
// on the server
Meteor.publish('posts', function(author) {
return Posts.find({flagged: false, author: author});
});
~~~
Definiamo questo parametro quando facciamo *sottoscrizione* a quella pubblicazione nel codice lato client della nostra applicazione:
~~~js
// on the client
Meteor.subscribe('posts', 'bob-smith');
~~~
Per rendere scalabile un'applicazione Meteor lato client, invece di sottoscrivere *ogni* dato disponibile, prendiamo e scegliamo le parti che sono necessarie. In questo modo evitiamo il sovraccarico della memoria del browser indipendentemente da quando è grande il database lato server.
### Come trovare i dati
I post di Bob sono divisi in più categorie (per esempio: "JavaScript", "Ruby" e "Phyton"). Potremmo voler ancora caricare tutti i post di Bob in memoria, ma vogliamo mostrare solo quelli della categoria "JavaScript". Vediamo come trovarli.
<%= diagram "collections-4", "Selezione di un sottoinsieme di documenti lato client.", "pull-center" %>
Come abbiamo fatto sul server, useremo la funzione `Posts.find()` per selezionare un sottoinsieme dei nostri dati:
~~~js
// on the client
Template.posts.helpers({
posts: function(){
return Posts.find({author: 'bob-smith', category: 'JavaScript'});
}
});
~~~
Ora che abbiamo più informazioni sul ruolo di pubblicazioni e sottoscrizioni, andiamo più a fondo e osserviamo alcuni schemi comuni di implementazione.
### Autopubblicazione
Se create un progetto Meteor da zero (ad esempio usando `meteor create`), verrà automaticamente abilitato il pacchetto `autopublish`. Come prima cosa vediamo esattemente cosa fa.
L'obiettivo di `autopublish` è di semplificare molto l'iniziare a scrivere codice in un'applicazione Meteor, replicando automaticamente _tutti i dati_ dal server al client, prendendosi carico di pubblicazioni e sottoscrizioni al posto nostro.
<%= diagram "autopublish", "Autopublish", "pull-center"%>
Come funziona? Supponiamo di avere una collezione chiamata `'posts'` sul server: `autopublish` invia automaticamente ogni post che trova nella collezione lato server in Mongo in una collezione chiamata `'posts'` sul client (assumendo che ne esista una).
Se state usando `autopublish`, non dovete preoccuparvi delle pubblicazioni. I dati sono dappertutto e le cose sono semplici. Ci sono ovvie problematiche legate al fatto di avere una copia completa del database dell'applicazione nella cache della macchina di ogni utente.
Per questo motivo autopublish è utile solo quando state iniziando e non avete ancora pensato alle pubblicazioni.
### Pubblicare intere collezioni
Dopo aver rimosso `autopublish` vi accorgerete presto che tutti i vostri dati sono spariti dal client. Un modo semplice per riverderli è di duplicare ciò che fa autopublish e pubblicare una collezione intera. Ad esempio:
~~~js
Meteor.publish('allPosts', function(){
return Posts.find();
});
~~~
<%= diagram "fullcollection", "Pubblicare una collezione intera", "pull-center" %>
Stiamo ancora pubblicando le intere collezioni ma abbiamo ora controllo su quali vogliamo mostrare. In questo caso stiamo pubblicando `Posts` ma non `Comments`.
### Pubblicare collezioni parziali
Il prossimo livello di controllo è di pubblicare solo _parte_ di una collection. Ad esempio solo i post che appartengono ad un certo autore:
~~~js
Meteor.publish('somePosts', function(){
return Posts.find({'author':'Tom'});
});
~~~
<%= diagram "partialcollection", "Pubblicare una collezione parziale.", "pull-center" %>
<% note do %>
### Dietro le quinte
Se avete letto la [documentazione di Meteor sulle pubblicazioni](http://docs.meteor.com/#publishandsubscribe), vi sarete forse preoccupati sentendo parlare di come usare `added()` e `ready()` per settare gli attributi dei record sul client e avrete faticato a capire come fare guardando le applicazioni di Meteor che non usano mai quei metodi.
Il motivo è che Meteor provvede una convezione molto importante: il metodo `_publishCursor()`. Non l'avete mai visto prima? Forse non direttamente ma se ritornate un [cursore](/chapter/meteor-vocabulary/) (ad esempio `Posts.find({'author':'Tom'})`) in una funzione di pubblicazione, è esattamente ciò che Meteor sta usando.
Quando Meteor vede che la pubblicazione `somePosts` ha ritornato un cursore, chiama `_publishCursor()` per -- avete indovinato -- pubblicare quel cursore automaticamente.
Questo è ciò che fa `_publishCursor()`:
- Controlla il nome della collezione lato server.
- Prende tutti i documenti risultanti e li invia ad una collezione lato client *con lo stesso nome* (Usa `added()` per farlo).
- Ogni volta che un documento viene aggiunto, rimosso o cambiato, invia questi cambiamenti alla collezione lato client (Usa `.observe()` sul cursore e `.added()`, `.changed()` e `removed()` per farlo).
In questo esempio possiamo essere sicuri di inviare all'utente solo i post a cui sono interessati (quelli scritti da Tom) disponibili nella cache lato client.
<% end %>
### Pubblicare proprietà parziali
Abbiamo visto come pubblicare alcuni dei nostri post ma possiamo andare ancora più a fondo! Vediamo come pubblicare solo specifiche *proprietà*.
Come prima, usiamo `find()` per ritornare un cursore, ma questa volta escludiamo alcuni campi:
~~~js
Meteor.publish('allPosts', function(){
return Posts.find({}, {fields: {
date: false
}});
});
~~~
<%= diagram "partialproperties", "Pubblicare proprietà parziali.", "pull-center" %>
Possiamo combinare entrambe le tecniche. Ad esempio, se vogliamo ritornare tutti i post di Tom ma non la loro data di pubblicazione, scriviamo:
~~~js
Meteor.publish('allPosts', function(){
return Posts.find({'author':'Tom'}, {fields: {
date: false
}});
});
~~~
### Riassumendo
Abbiamo visto come pubblicare ogni proprietà di ogni documento di ogni collezione (con `autopublish`) e come pubblicare solo _alcune_ proprietà di _alcuni_ documenti di _alcune_ collezioni.
Questo copre le basi di quello che si può fare con le pubblicazioni in Meteor, e queste semplici tecniche bastano a coprire la maggioranza dei casi.
Qualche volta avrete bisogno di andare oltre combinando, collegando oppure unendo le pubblicazioni. Vedremo come fare in un capitolo successivo!