How do you specify which fields are published to the client’s Meteor.users
collection? Using universal publications, obviously(1)! Let’s take a look at Meteor’s universal, or unnamed, publications and see how they’re used to accomplish this.
Put simply, a universal, or unnamed, publication is a publication without a name. That may not seem very special at first, but it raises some interesting questions in terms of functionality within the framework.
If a publication has no name, how do I subscribe to it?
You don’t! Universal publications are immediately and unconditionally started by the server and every connected client receives their data. Don’t take my word for it, it’s in the docs:
Name of the record set. If null, the set has no name, and the record set is automatically sent to all connected clients.
If I don’t subscribe to it, how do I know when the subscription is ready?
You don’t! The server never sends ready messages for universal publications. Universal publications just march to the beat of a different drummer.
What if I want to universally publish multiple collections?
Go for it! You can define as many universal publications as you’d like. Meteor does not check for duplicates like it does with named publications.
This does lead to an interesting point about multiple universal publications for a single collection. Imagine that a package, like accounts-base, sets up a universal publication for the Meteor.users
collection. Let’s pretend that this publication only returns the profile
, username
and emails
fields for each user.
What if we create another universal publication for the Meteor.users
collection that returns some other set of user fields like username
and roles
?
Meteor.publish(null, function() {
if (this.userId) {
return Meteor.users.find(
{_id: this.userId},
{fields: {username: 1, roles: 1}});
} else {
return null;
}
});
Interestingly enough, Meteor will run both of these publish handlers and publish the union of the fields returned by each. In our case, profile
, username
, emails
and roles
would all be published to the client!
So there’s the answer to our question. How do we publish more fields to the Meteor.users
collection? By creating a universal publication that publishes only the fields that we depend on.
Why don’t we just use named publications?
A named publication that publishes additional fields from the Meteor.users
collection will work, but you run the risk of accidentally dropping your subscription to that publication. I recently spend some time tracking down a fairly complicated bug in the Orion framework that dealt with this exact issue.
The Orion admin panel defined an adminUsers
publication that published additional fields on the Meteor.users
collection. It used these additional fields to determine if the current user had permission to view or modify content. The subscription to adminUsers
was maintained by SubsManager.
SubsManager only keeps around a certain number of subscriptions before dropping older subscriptions to make room for new ones. After navigating through the Orion admin panel for a few minutes, the old adminUsers
subscription was dropped to make room for a new subscription, which caused the Meteor.users
collection to fall back to universal publication defined by accounts-base.
This universal publication wasn’t publishing fields required by Orion (isAdmin
, permission
), so the Orion client was forced to assume that the client wasn’t authorized to view the current page.
The issue was fixed by creating a new universal publication in the Orion core package that returned the isAdmin
and permission
fields that the client depended on.
(1) This is not an obvious answer.