aei
aei

Reputation: 250

On demand Publish on Meteor?

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

Answers (2)

Kyll
Kyll

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:

  1. Publishing in a custom way, by adding a document to our publication,
  2. Remembering the publication handler for further updates,
  3. At a later time (here in an interval), use the remembered handlers to update the document.

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

Jordan Davis
Jordan Davis

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

Related Questions