Reputation: 250
Is there a way to publish updates to a collection only on demand? (e.g. send updates only every 5 seconds?)
I am publishing a leaderboard, which shows the the top 50 players (have the most points) in a game. Updates to users' points happen frequently, so that the leaderboard changes very often (every 1-5 seconds). Every minute or so, the server updates points for ~100 user in a forEach loop. The problem is that the publish methods start updating right away, before all the 100 elements have been updated. This creates a painful performance issue (publishing updates to all users multiple times)...
Is there a way to hold the publish until all the updates are done? Or a way to update the published data only every 5 seconds instead of immediately?
Thanks for your help! :)
Upvotes: 0
Views: 213
Reputation: 7151
Create a custom publication and take control!
var pubsHandlers = [];
Meteor.publish('totalScore', function() {
this.added('someClientCollection', 'totalScoreId', {
totalScore : someGetTotalScoreFunction()
});
pubsHandlers.push(this); //Maaaaybe not the cleanest thing to do.
this.ready();
});
Meteor.setInterval(function updateScores() {
var newTotalScore = somegetTotalScoreFunction()
pubsHandlers.forEach(function(pubHandler) {
pubHandler.changed('someClientCollection', 'totalScoreId', {
totalScore : newTotalScore
});
}, 5000); //Each 5 seconds, update everyone
So here's what's happening:
The main benefit is to keep the server in full control of the publication and its updates.
The main drawback is the use of push(this)
. It's not necessarily bad but it looks so damn hideous...
Upvotes: 1
Reputation: 1337
The article http://tomkelsey.co.uk/reining-in-the-reactivity-with-meteor/ discusses this exact issue, the author "used a combination of Meteor methods and the usual publication/subscription approach. A simplified example is set out below.
Within the onCreated method of the homepage I request a sorted array of item _ids from the server and save them into a session variable called itemIds:
Meteor.call('getItemIds', function(err, res) {
Session.set('itemIds', res);
});
On the server, the method is defined as:
Meteor.methods({
getItemIds: function() {
return Items.find({}, {fields: {_id: 1}, sort:
{rank:1}}).fetch();
}
});
I then watch for any changes to the itemIds session variable and (re)subscribe accordingly:
var self = this;
self.autorun(function() {
self.subscribe('itemsById', Session.get('itemIds'));
});
On the server, the publication looks like this:
Meteor.publish('itemsById', function(itemIds) {
return Items.find({}, {_id: {$in: itemIds}});
});
My template iterates over the itemIds array rather than the Items collection cursor. This means the order of items remains static.
For each _id within itemIds I can do an Items.find(_id) – the data will be in our client-side Items collection courtesy of our itemsById subscription.
Voila we have a list of reactive items that will retain its order until the page is refreshed."
Sound like it could be adapted for you :)
Upvotes: 0