Same subscription multiple times

I recently started using Meteor DevTools to see where I could optimize some parts of my code. I noticed in one place that I am making several subscription calls for the same user.

An example:

Template.registerHelper("getUser", userId => {
    Meteor.subscribe("userProfileInfo", userId);
    return Meteor.users.find({_id: userId}).fetch()[0];
});

I’m iterating over a list of messages, and subscribing to that user’s profile information to get his name and other things for that message. I noticed in the DevTools console that this is happening even if I’m already subscribed to the user, so I figured I would wrap it in an if statement.

In the template, within the {{#each messages}} block, I’m doing {{#with getUser userId}}. So this all seems to be working fine, until I view the DevTools and see that these calls are happening far too often and probably using unnecessary resources. So I decided to wrap the subscription in an if statement. Basically saying, hey if this user is already in our collection, don’t subscribe again, just return the user. When I did that, things went haywire. Multiple unsubscribes/resubscribes were happening. It wasn’t working at all.

So what is the correct way to optimize this?

Move the subscription out of the helper (it will activate whenever the template re-renders) and only call it whenever you need to update the userId value.

One approach:

Tracker.autorun(function () {
  var userId = Session.get('userProfileId');
  Meteor.subscribe('userProfileInfo', userId);
});

/* userId changed */
Session.set('userProfileId', newUserId);

If you’re not already using Session then I suggest using ReactiveDict instead (same thing but more powerful)

Thanks for the reply @reoh and though I understand what you’re saying, I don’t think this solves my issue of making a subscription call more than I have to. The userId of the message will change often, and often be a userId of a user we’re already subscribed to.

I ran into this a few months ago. I had a seperate sub for every user whos info I wanted. Because of the design of my app, I decided to approach the problem differently. I ended up using publish composite

Meteor.publishComposite('get_posts', function(c){
    return {
        find: function() {
              return db[c.dbname].find({"f_id" : c.f_id}, {limit:10, sort: {c_at: -1}} );
        },
        children: [
            {
                find: function(post) {
                    return get_owner(post);
                }
            },
        ]
    };
  }
});

function get_owner(post){
    return Meteor.users.find({ _id: post.u_id});
}

This way I have only one subscription and I still get all the user info i need

Thanks @intertwine, I’ve seen this package. This is interesting. Subscribe to all the information right away. I guess my design pattern is a little off, subscribing to the users at the time the message is getting displayed in the template… that’s definitely wrong.