I have the following code inside the onCreated() method of a template:
// Subscribe to notifications
instance.autorun(function() {
var limit = instance.limit.get();
var subscription = instance.subscribe('notificationsForUser', {
limit: limit
});
});
// Get user records for the senders
instance.autorun(function() {
var cursor = notificationsCollection.find();
var notifications = cursor.fetch();
var userIds = _.uniq(_.pluck(notifications, 'sender'));
if (_.difference(userIds, lastUserIds).length === 0) {
return; // lastUserIds is a global variable
}
lastUserIds = userIds;
instance.subscribe('usersById', userIds, {
fields: {
'username': 1,
'profile.firstName': 1,
'profile.lastName': 1,
'profile.avatar': 1
}
});
});
The first autorun gets notifications for a user from the database. The second autorun gets the ids of all users who sent a notification, removes any duplicates and hands it over to a subscription that retrieves the user records for these users.
The if clause was added to prevent unnecessary database queries. It checks if the new set of user ids is identical to the last autorun() and makes the autoron return immediately in this case.
Without this clause, the autorun works as expected. But if I add this if clause, the user collection will be cleared the second time the autorun() is running. It seems as if autorun() automatically unsubscribes from an earlier publication if it is not renewed. Is this true?
It seems to me as though your if statement does the clearing. From what I understand, the first time the autorun runs, it sets lastUserIds to userIds and makes the subscription, but then the second time it runs the autorun function returns, thus not going through with the subscription itself and therefore clears it.
If you want to optimize the reactivity, you could use tools such as
computation.firstRun
Tracker.afterFlush()
callback of the subscription itself (in fact you can carry over your whole second block into the callback of the notifications subscription’s callback)
Furthermore, you should not be needing such a hack to prevent extra database queries. As long as userIds remains the same, Meteor should be clever enough to reuse observers. To make it easier, you can sort the userIds array before handing it down.
If you call Meteor.subscribe within a reactive computation, for example using Tracker.autorun, the subscription will automatically be cancelled when the computation is invalidated or stopped; it’s not necessary to call stop on subscriptions made from inside autorun. However, if the next iteration of your run function subscribes to the same record set (same name and parameters), Meteor is smart enough to skip a wasteful unsubscribe/resubscribe
Interesting, thanks for that citation. Funny thing is that they do not explain that the subscription is discarded if you do not resubscribe. Or is that implied by “when the validation is … stopped”?