meteor / meteor-feature-requests

A tracker for Meteor issues that are requests for new functionality, not bugs.
Other
89 stars 3 forks source link

Have a way to subscribe to data without realtime updates #137

Open avalanche1 opened 7 years ago

avalanche1 commented 7 years ago

Migrated from: meteor/meteor#4814 tldr: Expected behaviour is to grab data from the server once using subscription API and then sever the connection, so that server doesn't have to allocate its resources for keeping the conneciton open.

We could grab data once with a Method, but subscription API is way lighter and doesn't require all the boilerwork that comes with Methods. Eg, I'd propose smth like {once: true} flag for subscription API.

mitar commented 7 years ago

Isn't this achievable by:

Meteor.publish('name', function (once) {
  check(once, Boolean):

  const handle = Collection.find().observeChanges({
    added: (id, fields) => {
      this.added('Collection', id, fields);
    },
    changed: (id, fields) => {
      this.changed('Collection', id, fields);
    },
    removed: (id) => {
      this.removed('Collection', id);
    }
  });

  this.onStop(() => {
    handle.stop();
  });

  this.ready();

  if (once) {
    // Stop subscription. Data will be removed from the client side.
    this.stop();
  }
});

Or, if you want a different semantics:

Meteor.publish('name', function (once) {
  check(once, Boolean):

  const handle = Collection.find().observeChanges({
    added: (id, fields) => {
      this.added('Collection', id, fields);
    },
    changed: (id, fields) => {
      this.changed('Collection', id, fields);
    },
    removed: (id) => {
      this.removed('Collection', id);
    }
  });

  this.onStop(() => {
    handle.stop();
  });

  this.ready();

  if (once) {
    // Stop handle. No reactivity from now on, but subscription is active.
    handle.stop();
  }
});
mitar commented 7 years ago

If you do not want to have once as an argument and you just always want no reactivity, things can be further simplified:

Meteor.publish('name', function () {
  const handle = Collection.find().observeChanges({
    added: (id, fields) => {
      this.added('Collection', id, fields);
    }
  });

  // Stop handle. No reactivity from now on, but subscription is active.
  handle.stop();

  this.ready();
});
aadamsx commented 7 years ago

@mitar anytime I hear about a Meteor client retrieving non-reactive data, it's suggested to use Meteor Methods. And it seems using Meteor Methods for non-reactive data DOES work. But one "flaw" I've seen with this approach is that we have to forgo Minimongo from what I can tell.

This is the first time I've seen a non-reactive Publish method. A big thank you for this!

A question, why use a Meteor Publish method over Meteor Methods for non-reactive data?

mitar commented 7 years ago

I think in general people couple too much things in Meteor. Just because Meteor comes with things nicely combined out of the box, MDG really made sure you can use things in other ways. You just have to think a bit out of the box. For example, publish can publish any data, not just data from MongoDB. For example, in the past I played with publishing data from ElasticSearch. Or even combine things, search from elastic search to get IDs, and then publish from Mongo to get reactivity on the content, but not the list of results.

formspoint commented 7 years ago

So for non-reactive data, you'd recommend using Publish for a Meteor Method most of the time?

avalanche1 commented 6 years ago

Mitar, does your solution supports the following?:

so that server doesn't have to allocate its resources for keeping the conneciton open

As far as i know, each connection to the client subscription - if it provides different data, eg a userId as an argument - requires some server resources to maintain that connection.

mitar commented 6 years ago

I would suggest you profile/benchmark things. If you do not keep connection, then you have to authenticate every query. Will that be better? I am not sure. Anyway, this is not a support forum.

avalanche1 commented 6 years ago

@aadamsx ,

we have to forgo Minimongo from what I can tell

You can create a static collection on the client const StaticData = new Mongo.Collection(null) and then populate it wit the data you've gotten from the method.