Pub/sub lifetime?


#1

Hi,
I am not sure about the lifetime of publications and subscriptions.
Let’s say I have a collection with 5000 entries (let’s say Songs, e.g. {artist:"U2", title:"One"}) and I do not want to publish everything to client, but I’ll have a search form on client and whenever the client selects a an artist, the server is publishing all the songs which belong to the artist. If this subscription is never killed, it will affect performance, so I am guessing I need to use the new template subscription (see Discover Blog). I have some questions though:

  1. I cannot use IronRouter waitOn and data context anymore, it’s not working with template level subscription, right?
  2. Where should I subscribe in client? in template.onCreated?
  3. How should I pass the artist selected by user to the template context? If it’s in route, I won’t be able to use template level subscription. In Session? Some other reactive variable?

What’s the best pattern for this use case?


#2

Do this:

Template.myTemplate.onCreated(function () {
  // This will get re-run when route changes
  this.autorun(function() {
    // Get the artist id from a route of the form:
    // http://www.www.com/zzzz?artistId=jjjjjj
    var artistId = Router.current().params.query.artistId;

    // Unsubscribe to old artist data and subscribe to new one    
    Meteor.subscribe('artist', artistId);
  });
});

Meteor.publish('artist', function(artistId) {
  // Unsubscribe all data when there is no artistId in the route
  if (!artistId)
    return this.ready();

  // Publish
  return Artists.find(artistId);
});

For better performance, you can replace line 6 by var artistId = isolateValue(function() { return Router.current().params.query.artistId; }) (see here).


#3

I did something like what you want, I think. I have a publish for the search query:

Meteor.publish("search", function (query) {
  var re = new RegExp(query, 'i');
  
  return Chart.find({"demographics.lastName": {$regex: re}}, {limit: 200, sort: {"demographics.lastName": 1}});
});

the helpers for the template to display the results:

Template.searchResults.helpers({
  searchString: function () {
    return Session.get('searchString');
  },
  theCharts: function () {
    var query = Session.get('searchString');
    searchSubsManager.subscribe("search", query);
    var re = new RegExp(query, 'i');
    var chartsFound = Chart.find({"demographics.lastName": {$regex: re}}, {limit: 200, sort: {"demographics.lastName": 1}});
        return chartsFound;
  }
});

and here’s the trick, using the SubsManager:

var searchSubsManager = new SubsManager({
  // keep the last 3 searches run
  cacheLimit: 3,
  expireIn: 5
});

as the comment says, doing this will only keep the last 3 searches on the client. Also, it will expire the search after 5 minutes as well.
Keeping the last 3 allows me to have someone search for, say Anders, then Anderson, then go back to Anders, and it will only hit the server twice, when the user goes back to Anders, it already has that result subscribed to and doesn’t go back to the server. Then, after 5 minutes, no updates will be sent to the client because the sub will be expired automatically.

to complete the example, I have this route:

Router.route('/search', {
  action: function () {
    this.render('searchResults');
  }
});

and the submit on the search form does this:

 'submit #searchForm': function (e) {
    e.preventDefault();
    var searchString = e.target.liveSearch.value;
    Session.setPersistent('searchString', searchString);
    Router.go('/search');
  }

Note: my solution doesn’t use autorun.

This works because the Session variable is reactive, so all I have to do is set the search string into the session on the submit event, then route to the search route, and the helper takes care of doing the subscription and finding the results.


#4

Hey Steve,
Meteor.subscribe('artist', artistId);
this is going to cleanup any previous subscription on client and server?

So basically in this case we shall have one active subscription until the template is again created with a new request, right?


#5

This is going to cleanup any previous subscription on client and server when, either:

  • the route changes (reason: subscribe is called within an autorun with the same ‘artist’ argument, so Meteor understands you want to change the same publication), or
  • the template is destroyed (reason: subscribe is called within a this.autorun, which is destroyed when the template is destroyed)

#6

Very useful info. How about Iron Router route subscriptions? Are those destroyed when the route is changed?


#7

I cannot help on this, sorry. I don’t manage subscription at the route level.