Subscription help

Hi. I have a collection that looks like

{
  name: 'whatever',
  servers: [ <an array of server _ids> ]
}

I have a publication that looks like this:

Meteor.publish("servers", function() {
  const user = User.current();
  if(user) {
    return Server.find({
      _id: {
        $in: user.servers
      }
    });
  } else {
    this.ready();
  }
});

My problem is when a server _id is added to the list of server _ids, the app doesn’t update that on the client.

My subscription is just using Tracker.autorun

  let servers = [];
  const computation = Tracker.autorun(() => {
    Meteor.subscribe('servers');
    const user = User.current();
    servers = Server.find({
      _id: {
        $in: user.servers
      }
    }).fetch();
  });

This isn’t re-run when user.servers changes. How can I get this behaviour?

I resolved this.

Publications aren’t inherently reactive. They don’t watch what’s being used, and re-run if something changes. From Meteor’s perspective,

return Server.find({
      _id: {
        $in: user.servers
      }
    });

never changes. This is the same query that ran originally, and nothing has changed.

The solution is to pass in your query as a parameter.

Meteor.publish("servers", function(ids) {
  if(this.userId) {
    return Server.find({
      _id: {
        $in: ids
      }
    });
  } else {
    this.ready();
  }
});

and subscribe with

  let servers = [];
  const computation = Tracker.autorun(() => {
    const user = User.current();
    Meteor.subscribe('servers', user.servers);
    servers = Server.find({
      _id: {
        $in: user.servers
      }
    }).fetch();
  });
1 Like

You can also use publish-composite to have reactive joined queries:

const userId = this.userId // or another user's id if it's allowed
find() {
  return Meteor.users.find(userId)
},
children: [
  {
    find(({ servers }) {
      return Server.find({ _id: { $in: servers }})
    }
  }
]
1 Like