Reactive Publish - Help please

Hi guys,

So I have a Meteor app that has a cron job running where every 1 minute it runs a bunch of calculations, insert the results on the DB and I want those results to be immediately published on the client.

I created the pub/sub model only to find out that MeteorJs does not reactivity in this model (do please correct me if I am wrong).

So, I tried these two libraries:

https://atmospherejs.com/lepozepo/reactive-publish
https://atmospherejs.com/peerlibrary/reactive-publish

For example, I did this:

Meteor.publish('arb', function itemsPublication() {
  this.autorun(function (computation) {
   return Item.find({});
 });
});

and in my client:

Template.Main.onCreated(function bodyOnCreated() {
  Meteor.subscribe('arb', {
    onReady: function () { console.log("onReady And the Items actually Arrive", arguments); },
    onError: function () { console.log("onError", arguments); }
  });
});

So when I load the page, I can see the onReady() function being called. I would expect to see that log being written every 1 minute. But it is not happening and the data is not being pushed to the client every minute.

Is there anything I might be doing wrong?

Thank you

Hi,

Meteor.publish('arb', function () { // Why itemsPublication ?
  this.autorun(function () { // No need Computation in your case ?
   return Item.find({});
 });
});

Look at https://docs.meteor.com/api/pubsub.html at the bottom. You can use also Tracker.

Tracker.autorun(() => {
  Meteor.subscribe('arb');
});

Hope it help.

Yeah - you’re wrong :slight_smile: - Meteor’s pub/sub model is expressly designed for reactivity. When used with MongoDB you get reactivity out of the box.

The template onCreated and onRendered lifecycle methods are only ever called once per template instance (btw, you should be using this.subscribe rather than Meteor.subscribe in your onCreated to get automatic lifecycle management of your subscriptions).

Reactivity in this use case comes from using template helpers. I recommend reading the Meteor Guide ahead of the API docs:

@Vandell: Using an autorun in a publication is discouraged (it’s not even documented). In a pub/sub context, they’re intended for subscriptions - and only then if the subscription has reactive parameters. Again, using Tracker directly is way beyond what’s needed here.

Hey there Vandell

Thank you very much for the help thus far!

When I add this.autorun(function () to my publish function, I am not getting the publishing at all in the client. The onReady() function does not get called.
When I remove the autorun, I do get the onReady(), but the changes on the model are not getting reflected.

Thanks for your help

Hi Rob, thank you for helping me out. I am only but new with Meteor, this is my first project. Do please excuse my general ignorance.

So here’s what I have so far:

In /server/publications/item.js:

import { Meteor } from 'meteor/meteor';
import Item from '../../lib/collections/item.js';

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

In /client/templates/home/home.js


import { Template } from 'meteor/templating';
import { Session } from 'meteor/session'
import Item from '../../../lib/collections/item.js';

Template.Main.onCreated(function bodyOnCreated() {

});

Tracker.autorun(() => {
  Meteor.subscribe('arb', {
    onReady: function () { console.log("onReady And the Items actually Arrive", arguments); },
    onError: function () { console.log("onError", arguments); }
  });
});

Template.Main.helpers({
    btcmindy() {
      return Item.findOne({key: {$eq: 'btcmindy'} });
    },
});

Now, I am expecting to see the “onReady” function being called every minute, in other words, every time a new insert is done in the model. But this is not happening.

What do you think I am doing wrong?

Thank you!

Same thing here :

Template.Main.onCreated(function bodyOnCreated() { // remove this `bodyOnCreated`

As @robfallows use this.subscribe('arb', {. in the OnCreated function().

Template.Main.onCreated(function () {
  this.subscribe('arb', {
    onReady: function () { console.log("onReady And the Items actually Arrive", arguments); },
    onError: function () { console.log("onError", arguments); }
  });
});

Im not using Blaze sry but try it

Seamless Meteor.subscribe issue

Once the subscription is set up (ready) it will not be run again.

I would start simple. Your publication is fine. It returns the entire collection, which is okay if it’s reasonably small (less than a few hundred docs).

However, you can simplify your client code:

import { Template } from 'meteor/templating';
import Item from '../../../lib/collections/item.js';

Template.Main.onCreated(function bodyOnCreated() {
  this.subscribe('arb');
});

Template.Main.helpers({
  btcmindy() {
    return Item.findOne({ key: 'btcmindy' });
  },
});

Other comments I should make:

  1. The btcmindy helper will rerun whenever the document located by key: 'btcmindy' changes. If that document never changes, the helper will not rerun.
  2. If you are adding many documents with a key of 'btcmindy' you should be using find, not findOne in your helper.
  3. You need to use a Blaze template to see the results (or you could console.log in the helper code).
  4. You should be importing { Item }, not Item. Also, see the next point.
  5. You are importing from lib/ - that’s actually unnecessary - files in lib/ are always loaded on both client and server. I’d be inclined to create imports/both/collections/ and put your item.js in there. Then do import { Item } from '/imports/both/collections/item'; in your client and server modules - it’s easier to grok than ../../...

Hi,

Ok, so my real issue is my mongodb update. It is not actually updating the record. This is my method:

function upsertItem(_key, pct) {
  var thisItem = Item.findOne({key: _key});
  if(thisItem != undefined) {
     Item.update({_id: thisItem.id}, { $set: { percentage: pct } });
  } else {
    Item.insert({
      key:_key,
      percentage:pct,
      createdAt: new Date()
    });
  }
}

No updating though, I query the DB and it has the same pct value. Any clue guys?

EDIT:
Found the issue:

Item.update({_id: thisItem.id}, { $set: { percentage: pct } });

It should be
Item.update({_id: thisItem._id}, { $set: { percentage: pct } });

It works now! Hoooray to reactivity!

Thank you so much guys for all the help

Happy that you find your issue :stuck_out_tongue_winking_eye:. Thx to @robfallows