Meteor publish subscribe is not reactive
javascript, meteor, mongodb, node.js
Solution
This (excellent) article might help. To paraphrase:
...on the server, Meteor’s reactivity is limited to cursors returned by Meteor.publish() functions. The direct consequence of this is that unlike on the client, code will not magically re-run whenever data changes.
Problem
My client subscription routines are not refreshing when I update a collection: server/publish.js ``` Meteor.publish('decisions', function (decisionCursor) { return Decisions.find({ active: true }, { limit: 20, skip: decisionCursor }); }); Meteor.publish('decisionsToModerate', function (decisionCursor) { return Decisions.find({ active: false }, { sort: { createdAt: -1 }, limit: 1, skip: decisionCursor }); }); ``` I subscribe my client to both collection publications and when it fetchs all data it creates a session object with some stuff I need. client/client.js ``` Meteor.startup(function () { SimpleSchema.debug = true; Deps.autorun(function () { Meteor.subscribe("decisions", Number(Session.get('decisionCursor')), function () { var decisionsVoted = {}; Decisions.find({ active: true }).forEach(function (decision) { var userVoted = Meteor.users.findOne({ "_id": Meteor.userId(), "profile.votes.decision": decision._id }) != null ? Meteor.users.findOne({ "_id": Meteor.userId(), "profile.votes.decision": decision._id }) : false; var ipVoted = Votes.findOne({ "ip": headers.get('x-forwarded-for'), "votes.decision": decision._id }) != null ? true : false; if (ipVoted || userVoted) decisionsVoted[decision._id] = { voted: true, blue: decision.blueTotal, red: decision.redTotal, bluePer: Math.round(decision.blueTotal * 100) / (decision.blueTotal + decision.redTotal), redPer: Math.round(decision.redTotal * 100) / (decision.blueTotal + decision.redTotal) }; }); Session.set('decisionsVoted', decisionsVoted); }); Meteor.subscribe("decisionsToModerate", Number(Session.get('decisionCursor'))); }); }); ``` client/lib/environment.js ``` activeDecisions = function() { var decisions = Decisions.find({active: true}); console.log(decisions.fetch().length); return decisions; }; moderateDecisions = function() { return Decisions.find({active: false}); }; ``` client/views/home/home.js ``` 'click': function (event) { event.preventDefault(); var decisionId = Session.get("selected_decision"); var hasVoted = Session.get('decisionsVoted')[decisionId] ? Session.get('decisionsVoted')[decisionId].voted : false; Meteor.call("vote", decisionId, 'blue', hasVoted, function (error, result) { if (!error && result === true) { console.log(Session.get('decisionsVoted')[decisionId]); // UNDEFINED } }); }, ``` When updating is successful, client subscriptioun should update creating a new object in my session object, right? Because collection is changed so publish in server is refreshed... But it does not refresh and what I commented `// UNDEFINED` instead of returning my new object is returning `UNDEFINED` I don't know if that's the behaviour of Meteor or I'm missing something... I've tried to update parameter passed to publish method `decisionCursor` in order to force update but nothing hapens `Session.set('decisionCursor', Session.get('decisionCursor'));` EDIT: it seems that if I use `Session.set('decisionCursor', Session.get('decisionCursor') + 1);` (note that +1) it is refreshed but not inside result function, if I click again it detects that new object is added... But I need it to be refreshed inside result function (inside my `home.js` click event)