The BasicsPublications and Subscriptions

In Meteor, publications and subscriptions are the glue between data, the client, and the server. Data is stored in the MongoDB database and retrieved using publications. A publication specifies what data needs to be retrieved from the collection—also implementing some security in respect to who can access that data and when—and responds to subscription requests from subscriptions on the client.

Publication, subscription diagram.
Publication, subscription diagram.

Subscriptions work by connecting to a specific publication defined on the server. Once it's established, the publication will send all of the data it's configured to send to the client. On the client, Meteor implements a client-side data cache (i.e., a database in the browser) called minimongo.

While a subscription is established, data flows between the publication and the subscription with documents being stored in minimongo. Once a subscription is stopped, any documents sent by the publication to the subscription on the client are removed from minimongo.

In Pup, the subscription portion of this equation takes place inside of a data container wrapped around a React component. While subscriptions can be established from anywhere on the client, doing so inside of a container ensures that any React component dependent on the data from a subscription stays up to date, and, when the component is removed from screen, the subscription is stopped.

Example Publication (Server)
import { Meteor } from 'meteor/meteor';

Meteor.publish('tacos', function() {
  return Tacos.find();
Example Subscription (Client)
const subscription = Meteor.subscribe('tacos');

Documents publications

In Pup, there are two publications defined for sharing data from the Documents collection:

documents supplies the subscription with all of the documents in the Documents collection where the owner field is equivalent to the current user's _id value. As a convenience, Meteor gives us the current user's _id value via the this.userId variable. this refers to the callback function to the documents publication. Of note, we use a standard function—not an ES2015/ES6 arrow function—because this must refer to the publication scope and not the parent scope (inside of arrow functions this refers to the parent scope, not the immediate function's scope).

Related Subscriptions: /imports/ui/pages/Documents/Documents.js.

documents.view supplies the subscription with a single document in the Documents collection, matching the documentId passed from the client to the subscription (Meteor.subscribe('documents.view', <documentId>);). Following a similar approach the documents publication, documents.view checks to see if the owner of the found document is equal to this.userId.

Related Subscriptions: /imports/ui/pages/ViewDocument/ViewDocument.js, /imports/ui/pages/EditDocument/EditDocument.js.

Notice: the documents.view publication uses the check() method just like a method. Just like methods, publications are watched for their usage of check() on arguments via the audit-argument-checks Atmosphere (Meteor) package.
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Documents from '../Documents';

Meteor.publish('documents', function documents() {
  return Documents.find({ owner: this.userId });

// Note: documents.view is also used when editing an existing document.
Meteor.publish('documents.view', function documentsView(documentId) {
  check(documentId, String);
  return Documents.find({ _id: documentId, owner: this.userId });

Users publications

In Pup, there is one publication defined for sharing data from the Meteor.users collection:

users.editProfile supplies the subscription with data related to the currently logged-in user's profile. This includes their email address, profile (with name field), and services. services is included as this is where Meteor stores OAuth account data. If a user has logged-in via OAuth, Pup checks for this and displays a block in the user's profile letting them know that they logged in with that service.

Related Subscriptions: /imports/ui/pages/Profile/Profile.js

import { Meteor } from 'meteor/meteor';

Meteor.publish('users.editProfile', function usersProfile() {
  return Meteor.users.find(this.userId, {
    fields: {
      emails: 1,
      profile: 1,
      services: 1,