Kolekcje, publikacje i subskrypcje to trudny obszar Meteoru, który dokumentacja mogłaby omówić bardziej szczegółowo, aby uniknąć częstych nieporozumień, które czasami są wzmacniane przez mylącą terminologię.
Oto Sacha Greif (współautorka DiscoverMeteor) wyjaśniająca publikacje i subskrypcje na jednym slajdzie:
Aby właściwie zrozumieć, dlaczego musisz wywołać find()
więcej niż raz, musisz zrozumieć, jak działają kolekcje, publikacje i subskrypcje w Meteor:
-
Kolekcje definiujesz w MongoDB. Nie ma jeszcze Meteora. Te kolekcje zawierają rekordy bazy danych (nazywane również „dokumentami” zarówno przez Mongo, jak i Meteor, ale „dokument” jest bardziej ogólny niż rekord bazy danych; na przykład specyfikacja aktualizacji lub selektor zapytania również są dokumentami – obiekty JavaScript zawierające
pole:wartość par).
-
Następnie definiujesz kolekcje na serwerze Meteor z
MyCollection = new Mongo.Collection('collection-name-in-mongo')
Te kolekcje zawierają wszystkie dane z kolekcji MongoDB i możesz uruchomić
MyCollection.find({...})
na nich, co zwróci kursor (zestaw rekordów wraz z metodami ich iteracji i zwracania). -
Ten kursor jest (przez większość czasu) używany do publikowania (wyślij) zestaw rekordów (zwany "zestawem rekordów" ). Opcjonalnie możesz opublikować tylko niektóre pola z tych rekordów. To zestawy rekordów (nie kolekcje), które klienci subskrybują do. Publikowanie odbywa się za pomocą funkcji publikowania, która jest wywoływana za każdym razem, gdy subskrybuje nowy klient i która może przyjmować parametry do zarządzania rekordami do zwrócenia (np. identyfikator użytkownika, aby zwrócić tylko dokumenty tego użytkownika).
-
Na kliencie , masz kolekcje Minimongo, które częściowo lustro niektóre rekordów z serwera. "Częściowo", ponieważ mogą zawierać tylko niektóre pola, i "niektóre z rekordów", ponieważ zazwyczaj chcesz wysłać do klienta tylko te rekordy, których potrzebuje, aby przyspieszyć ładowanie strony i tylko te, których potrzebuje i ma pozwolenie na dostęp.
Minimongo jest zasadniczo nietrwałą implementacją Mongo w pamięci w czystym JavaScript. Służy jako lokalna pamięć podręczna, która przechowuje tylko podzbiór bazy danych, z którą pracuje ten klient. Zapytania na kliencie (znajdź) są obsługiwane bezpośrednio z tej pamięci podręcznej, bez komunikowania się z serwerem.
Te kolekcje Minimongo są początkowo puste. Wypełnia je
Meteor.subscribe('record-set-name')
wzywa. Zauważ, że parametr do zasubskrybowania nie jest nazwą kolekcji; to nazwa zestawu rekordów serwer używany w
opublikowaniu
połączenie.subscribe()
wywołanie subskrybuje klienta do zestawu rekordów - podzbiór rekordów z kolekcji serwera (np. 100 ostatnich postów na blogu), ze wszystkimi lub podzbiorem pól w każdym rekordzie (np. tylkotytuł
idata
). Skąd Minimongo wie, w której kolekcji umieścić przychodzące rekordy? Nazwą kolekcji będziekolekcja
argument używany wadded
procedury obsługi publikowania ,zmieniono
iusunięty
wywołania zwrotne, lub jeśli ich brakuje (co ma miejsce w większości przypadków), będzie to nazwa kolekcji MongoDB na serwerze.
Modyfikowanie rekordów
W tym miejscu Meteor sprawia, że wszystko jest bardzo wygodne:kiedy zmodyfikujesz rekord (dokument) w kolekcji Minimongo na kliencie, Meteor natychmiast zaktualizuje wszystkie szablony, które od niego zależą, a także odeśle zmiany z powrotem na serwer, który z kolei zapisze zmiany w MongoDB i wyśle je do odpowiednich klientów, którzy zasubskrybowali zestaw rekordów zawierający ten dokument. Nazywa się to kompensacją opóźnień i jest jedną z siedmiu podstawowych zasad Meteoru.
Wiele subskrypcji
Możesz mieć kilka subskrypcji, które pobierają różne rekordy, ale wszystkie trafią do tej samej kolekcji na kliencie, jeśli pochodzą z tej samej kolekcji na serwerze, na podstawie ich _id
. Nie jest to jasno wyjaśnione, ale sugerowane w dokumentacji Meteor:
Kiedy subskrybujesz zestaw rekordów, nakazuje serwerowi wysłanie rekordów do klienta. Klient przechowuje te rekordy w lokalnych kolekcjach Minimongo o tej samej nazwie co kolekcja
argument używany w added
procedury obsługi publikowania , zmieniono
i usunięty
wywołania zwrotne. Meteor będzie kolejkować przychodzące atrybuty, dopóki nie zadeklarujesz Mongo.Collection na kliencie z pasującą nazwą kolekcji.
Nie wyjaśniono, co się dzieje, gdy nie jawnie użyj dodano
, zmieniono
i usunięty
, lub w ogóle publikuj programy obsługi — co jest w większości przypadków. W tym najczęstszym przypadku argument kolekcji jest (nie dziwi) wzięty z nazwy kolekcji MongoDB, którą zadeklarowałeś na serwerze w kroku 1. Oznacza to jednak, że możesz mieć różne publikacje i subskrypcje o różnych nazwach, a wszystkie rekordy znajdą się w tej samej kolekcji na kliencie. Aż do poziomu pól najwyższego poziomu , Meteor dba o wykonanie ustalonej unii między dokumentami, tak aby subskrypcje mogły się nakładać - publikuj funkcje, które wysyłają różne pola najwyższego poziomu do klienta, pracują obok siebie i na kliencie, dokument w kolekcji będzie unią tych dwóch zestawy pól.
Przykład:wiele subskrypcji wypełnia tę samą kolekcję na kliencie
Masz kolekcję BlogPosts, którą deklarujesz w ten sam sposób zarówno na serwerze, jak i na kliencie, mimo że robi ona różne rzeczy:
BlogPosts = new Mongo.Collection('posts');
Na kliencie BlogPosts
można pobrać rekordy z:
-
subskrypcja ostatnich 10 wpisów na blogu
// server Meteor.publish('posts-recent', function publishFunction() { return BlogPosts.find({}, {sort: {date: -1}, limit: 10}); } // client Meteor.subscribe('posts-recent');
-
subskrypcja postów bieżącego użytkownika
// server Meteor.publish('posts-current-user', function publishFunction() { return BlogPosts.find({author: this.userId}, {sort: {date: -1}, limit: 10}); // this.userId is provided by Meteor - http://docs.meteor.com/#publish_userId } Meteor.publish('posts-by-user', function publishFunction(who) { return BlogPosts.find({authorId: who._id}, {sort: {date: -1}, limit: 10}); } // client Meteor.subscribe('posts-current-user'); Meteor.subscribe('posts-by-user', someUser);
-
subskrypcja najpopularniejszych postów
- itd.
Wszystkie te dokumenty pochodzą z postów
kolekcja w MongoDB, za pośrednictwem BlogPosts
kolekcja na serwerze i trafia do BlogPosts
odbiór na kliencie.
Teraz możemy zrozumieć, dlaczego musisz wywołać find()
więcej niż raz - drugi raz będąc u klienta, bo dokumenty ze wszystkich abonamentów trafią do tej samej kolekcji, a Ty musisz pobierać tylko te, na których Ci zależy. Na przykład, aby uzyskać najnowsze posty na kliencie, po prostu odzwierciedlasz zapytanie z serwera:
var recentPosts = BlogPosts.find({}, {sort: {date: -1}, limit: 10});
Spowoduje to zwrócenie kursora do wszystkich dokumentów/rekordów, które klient otrzymał do tej pory, zarówno najlepszych postów, jak i postów użytkownika. (dzięki Geoffrey).