Search code examples
javascriptmeteorreactive-programmingmeteor-publications

Preventing Meteor from removing MiniMongo data already sent to client when publish changes


I have noticed that when I change the published cursor - NOT the data the cursor points to, but the whole cursor - Meteor will send a removed message to the client for all documents that do not appear in the new cursor. What I mean in more technical terms:

// client side
Tracker.autorun(function() {
    var someReactiveVar = someReactiveVar.get(); 
    Meteor.subscribe('myPublication', someReactiveVar);
}
...
// server side
Meteor.publish('myPublication', function() {
    var someParameter = arguments[0];
    return myCollection.find({ someAttribute: someParameter });
});

Now when someReactiveVar changes, all documents that had been sent to the client side MiniMongo myCollection will be removed (if they are not part of the new cursor). In certain cases this is what you will want, but my question simply is: can I prevent this? How?


Solution

  • There's some magic happening here, when you perform Meteor.subscribe inside a Tracker.autorun. Basically, it will .stop() the old subscription after each run.

    You have two options,

    1- Keep multiple subscriptions alive, by using a nonreactive block.

    Note: You'll have to write some code to clean-up subHandles.

    var subHandles = [];
    Tracker.autorun(function(){
      var someReactiveVal = someReactiveVar.get();
      Tracker.nonreactive(function(){
        var subHandle = Meteor.subscribe('myPublication', someReactiveVal);
        subHandles.push(subHandle);
      });
    });
    

    2- Make your subscription take multiple values, eg

    Note: This will make both sets of data available on the client, but may not stop it being re-transmitted.

    Template.myTemplate.events({
       'click mybutton': function(){
          var newVal = getNewVal();
          var arrayOfValues = someReactiveVar.get();
          arrayOfValues.push(newVal);
          someReactiveVar.set(arrayOfValues);
       }
    })
    
    // client side
    Tracker.autorun(function() {
        var arrayOfValues = someReactiveVar.get(); 
        Meteor.subscribe('myPublication', arrayOfValues);
    }
    ...
    // server side
    Meteor.publish('myPublication', function(arrayOfValues) {
        return myCollection.find({ 
          someAttribute: {$in: arrayOfValues} 
        });
    });