0

I have done a Simple Publish/subscribe in my meteor project and whenever User lands on home page I have to show count of total users. Users are around 15000. Now in template helper I have code written a code as,

CLIENT-SIDE

Template.voters.helpers({
  voters : function() {
   return voters.find({});
  },
  count :  voterscount
  });

then on SERVER-SIDE

voters = new Mongo.Collection("voters");
voterscount = function() {
    return voters.find({}).count();
}

Meteor.publish('voters', function() {
    return voters.find({});
  });

Meteor.publish('voterscount', function() {
    return voterscount;
  });
  1. The output that I receive is that the count starts from 0 to 15000 on UI Which is irritating.
  2. I don't want rolling up of the digits on UI and should show the static count on UI as 15000 whenever page refreshed.
  3. Why is this so slow it. In production i will have around 10 million documents in collection. This is big drawback. Any help, please?
Ankur Soni
  • 5,725
  • 5
  • 50
  • 81
  • Does it absolutely need to be 100% accurate? I'd approach this differently: get the actual value every say 5 minutes, cache it and then increment it slightly for every second since the value was last cached. – Michael May 05 '16 at 15:40
  • You can't publish `voterscount` like that. A publication can only return a cursor or array of cursors. – Michel Floyd May 05 '16 at 19:59
  • Also, are you subscribing to `voters` on the client? That would be slow. – Michel Floyd May 05 '16 at 20:21

2 Answers2

2

This is a good use case for a universal publication, i.e. one that is automatically sent to all clients.

Server:

stats = new Mongo.collection('stats'); // define a new collection
function upsertVoterCount(){ 
  stats.upsert('numberOfVoters',{ numberOfVoters: voters.find().count() });
}
upsertVoterCount();

Meteor.publish(null,function(){ // null name means send to all clients
  return stats.find();
});

var voterCursor = voters.find();
voterCursor.observe({
  added: upsertVoterCount,
  removed: upsertVoterCount
});

Then on the client you can get the voter count anytime with:

var nVoters = stats.findOne('numberOfVoters').numberOfVoters;
Michel Floyd
  • 18,793
  • 4
  • 24
  • 39
  • Won't that calculate the count only on server start? I used the method described in the docs (http://docs.meteor.com/#/full/meteor_publish), also in this answer (http://stackoverflow.com/questions/10565654/how-does-the-messages-count-example-in-meteor-docs-work). I didn't know about the null name for publish, that is a good trick. – Nicolas Galler May 06 '16 at 00:05
  • The `.observe()` will run every time a voter is added/removed. – Michel Floyd May 06 '16 at 00:07
  • Michel... you should definitely write a book. I will try this today! – Ankur Soni May 06 '16 at 03:27
  • You're too kind Ankur! – Michel Floyd May 06 '16 at 04:24
  • @Michel, The code snippet that you gave it to us give error for $exist operator for findOne. The Collection.upsert() does not work only with one parameters. It needs minimum two parameters and . I have tried and tested the peice of code and adding it below for you to review – Ankur Soni May 06 '16 at 08:44
  • Thanks Ankur! I've modified my answer accordingly. Sorry I didn't have a chance to test it before, I miss meteorpad :( – Michel Floyd May 06 '16 at 16:26
0

SERVER-publish.js

function upsertVoterCount(){ 
   voterscount.upsert('numberOfVoters',
     { 
        numberOfVoters : voters.find().count() 
     });
}


// null name means send to all clients
Meteor.publish(null ,function() { 
    upsertVoterCount();
    return voterscount.find();
});

var voterCursor = voters.find();

voterCursor.observe({
  added: upsertVoterCount,
  removed: upsertVoterCount
});

LIB-collection.js

// define a new collection
voterscount = new Mongo.Collection('voterscount'); 

CLIENT-home.js

Template.voter.helpers({
  count :  function() {
    return voterscount.findOne().numberOfVoters;
  }
});
Ankur Soni
  • 5,725
  • 5
  • 50
  • 81