Same subscription multiple times


#1

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?


#2

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)


#3

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.


#4

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


#5

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.