TJR
TJR

Reputation: 6577

meteorjs stop subscribtion of collection

I want to stop a subscribtion process.

Currently this is my code:

if (Meteor.isClient) {

    Meteor.autorun(function(){
        var query;
        query = Session.get('search.query');
        if (!query) return;
        if (Envi.temp.searchSubscribtion) {
            console.log('Subscribtion for search has to stop ... ');
            Envi.temp.searchSubscribtion.stop();
        }

        Envi.temp.searchSubscribtion = Meteor.subscribe('search', query, {
            onReady : function () {
                console.log('Finished.');
            }
        });
    });

}

Env is a global function where I temporaly save the subscribtions in temp.searchSubscribtion.

The problem now: I change the search.query value to a query to get all items. The finished console.log "Finished" displays after about 1 minute.

After this I change the search.query to a query which jsut get a few items. The Finished console.log displays after about 5 seconds.

As you see: A long query, and a small one.

What I want to do now is:

When a query was changed the currently subscribtion has to be canceld and the new subscribtion has to start, but:

When I set the long query and right(!) after this I change the search.query Session to the small query the "Finished" console.log displays after more than 1 minute.

The "Envi.temp.searchSubscribtion.stop();" executes rigth (I see the console log) but the susbcribtion does not stop - it seems that the server just finish the first susbcribtion and than finish the second one - like a queue.

Any ideas how to cancel a running subscribtion ?

Upvotes: 0

Views: 67

Answers (1)

nathan-m
nathan-m

Reputation: 8865

Because the original query is taking that time to return, the single Fiber that runs your subscriptions will be stalled. You wont be able to send it any other subscription commands (stop / new subscription etc) until it completes.

You have a few options:

  1. Make the query faster (indexes?)
  2. Publish all documents [perhaps limit some fields], then search on the client. You can then subscribe to the full set of fields by sending a list of _id's
  3. Don't use a publication, and send the data via Meteor.methods (non-reactive/auto-publish).
  4. Combine 2 & 3; call a meteor method to do the query, that just returns a list of _id's, then subscribe to that list of _id's
  5. Do (4) except use a server-side route, to avoid blocking up meteor methods (if you're firing off a lot of method calls... )

Just be careful when using Meteor.methods to avoid blocking fibers you'll need to:

  1. call from the client with Meteor.apply('myMethod',[parameter1, parameter2 /* etc */], {wait: false}, callback);
  2. on the server call this.unblock() in the method body.

An example of (4):

if (Meteor.isServer) {
  Meteor.methods('search', function (query) {
    this.unblock();
    // some query logic??
    return _.pluck(collection.find(query, {_id: true}).fetch(), '_id');
  });

  Meteor.publish('searchResults', function (resultIds) {
    return collection.find({_id: {$in: resultIds}});
  });

}
if (Meteor.isClient) {

  Meteor.autorun(function () {
    var query;
    query = Session.get('search.query');
    if (!query) return;
    Meteor.apply('search', [query], {wait:false}, function (err, resultIds) {
      if (err) {
        console.log('error!', err);
        return;
      }
      var currentSearch = Session.get('search.query');
      if (!EJSON.equals(currentSearch, query)) {
        console.log('Results returned for', query, ' however current search is ', currentSearch);
        return;
      }

      if (Envi.temp.searchSubscribtion) {
        console.log('Subscribtion for search has to stop ... ');
        Envi.temp.searchSubscribtion.stop();

      }
      Envi.temp.searchSubscribtion = Meteor.subscribe('searchResults', resultIds, {
        onReady: function () {
          console.log('Finished for query:', query);
        }
      });
    });
  });

}

Upvotes: 1

Related Questions