Search code examples
meteorreactive-programmingmeteor-publications

Publish reactive collection summary data


I have a collection but don't want to publish it all to client because it's huge, however I need to publish some stats from this collection (as count, sum, avg, etc).

I can't use methods because they are not reactive and also I can't use publish because it works only with cursor.

I have an idea to create additional collection and store these stats in it, but this looks a bit strange.

What the best way to do it?

Solution

On server side:

Meteor.publish('myStats', function() {
  var self = this;
  var initializing = true;
  var stats = {};
  var filter = {/* Your filter if needed */};

  var calcStats = function() {
    stats = {stat1: 0, stat2: 0}; // Init stats
    var mc = MyCollection.find(filter).fetch();

    for (var i = 0; i < mc.length; i++) {
      doc = mc[i];

      // Here any logic to calculate stats
      stats.stat1 += 1;
      stats.stat2 += doc.field;
      // ...
    }

    if (!initializing) {
      return self.changed('myStats', 'stringId', stats);
    }
  };

  MyCollection.find(filter).observeChanges({
    added: calcStats,    // I will recalculate all my stats
    changed: calcStats,  // after any changes happend
    removed: calcStats
  });

  initializing = false;
  this.added('myStats', 'stringId', stats);
  return this.ready();
});

Create collection on client side:

MyStats = new Mongo.Collection('myStats');

Use stats:

Meteor.subscribe('myStats');
var stats = MyStats.findOne('stringId');

Solution

  • You can use meteor methods if you like. You simply need to store the results of your meteor method call in a reactive variable, for example, a session variable.

    Template.templateName.onRenedered( function() {
      Meteor.call("getStats", function(err, res) {
        Session.set("count", res.count); // for example
      }
    });
    

    You can also take a look at the reactive-var package to create your own reactive variables, which you can attach to templates rather than polluting the global session.

    Edit: this may not solve your problem of it being not reactive. Take a look at this answer: How to 'transform' data returned via a Meteor.publish?. Here you can change the data you are publishing, mapping your cursor to something less large while adding the fields you need.