jam:pub-sub brings three key features to Meteor apps:
- Method-based publish / subscribe with reactivity for the user when they make database writes
- Change Streams-based publish / subscribe
- Subscription caching
Method-based publish / subscribe
Meteor’s traditional publish / subscribe
is truly wonderful. However, there is a cost to pushing updates reactively to all connected clients – it’s resource intensive and will eventually place limits on your ability to scale your app.
One way to reduce the need for the traditional publish / subscribe
is to fetch the data via a Meteor Method
but there’s a big problem here: the data won’t be automatically merged into Minimongo and you completely lose Meteor’s magical reactivity. Minimongo is great to work with and makes things easy as the source of truth on the client. Without it, you’ll need to create your own stores on the client and essentially duplicate Minimongo.
With jam:pub-sub
, you use Meteor.publish.once
and the same Meteor.subscribe
to have the data fetched via a Meteor Method and merged automatically in Minimongo so you can work with it as you’re accustomed to. It also automatically preserves reactivity for the user when they make database writes. Note that these writes will not be broadcast in realtime to all connected clients by design but in many cases you might find that you don’t need that feature of Meteor’s traditional publish / subscribe
.
Here’s a quick look on how you use it:
Create a publication using Meteor.publish.once
// server
Meteor.publish.once('notes.all', function() {
return Notes.find(); // expects a cursor or an array of cursors just like Meteor.publish
});
Subscribe like you normally would on the client:
// client
Meteor.subscribe('notes.all')
That’s it. By using Meteor.publish.once
, it will fetch the data initally and automatically merge it into Minimongo. Any database writes to the Notes
collection will be sent reactively to the user that made the write.
Change Streams-based publish / subscribe
With jam:pub-sub
and MongoDB Change Streams, you can preserve Meteor’s magical reactivity for all clients while opting out of the traditional publish / subscribe
and its use of the oplog
. Use Meteor.publish.stream
instead of using Meteor.publish
and subscribe using the same Meteor.subscribe
on the client.
Here’s a quick look on how you use it:
Create a publication using Meteor.publish.stream
// server
Meteor.publish.stream('notes.all', function() {
return Notes.find(); // expects a cursor or an array of cursors just like Meteor.publish
});
Subscribe like you normally would on the client:
// client
Meteor.subscribe('notes.all')
That’s it. By using Meteor.publish.stream
, any database writes to the Notes
collection will be sent reactively to all connected clients just as with Meteor.publish
but you’ll be using MongoDB Change Streams instead of the oplog.
Subscription caching
Normally, when a user moves between routes or components, the subscriptions will be stopped. When a user is navigating back and forth in your app, each time will result in a re-subscribe which means more spinners, a slower experience, and is generally a waste.
By caching your subscriptions, you can create a better user experience for your users. Since the subscription itself is being cached, the data in Minimongo will be updated in the background until the cacheDuration
expires for that subscription at which point it will be stopped and the data will be removed from Minimongo as expected.
If you’re familiar with ccorcos:subs-cache
or other subscription cache managers, this would act as a replacement.
It’s not enabled by default to align with the current Meteor.subscribe
behavior. You can turn it on globally for all subscriptions:
import { PubSub } from 'meteor/jam:pub-sub';
PubSub.configure({
cache: true // defaults to false
});
Or you can turn it on for individual subscriptions when you subscribe:
Meteor.subscribe('notes.all', { cache: true }) // overrides the global PubSub config
You can also customize the cacheDuration
globally and/or when you subscribe. The default is 1 minute from when the component was destroyed and the subscription was initially set to stop.
If you end up taking it for a spin, let me know! If you have feedback, feel free to post below or send me a DM.