Ankur Soni
Ankur Soni

Reputation: 6018

How to know if Meteor Collection Subscription did not change. [Meteor + Blaze]

Below is the piece of subscription on UI.

Template.AssociateEmp.onCreated(function(){
    this.validEmail = new ReactiveVar('');

    const tpl = this;
    this.autorun(() => {
        var email = this.validEmail.get();
        this.subscribe('GetUnassociatedUser', email, {
            onReady: function () {},
            onError: function () {}
          });
    });
});

Is there a way to know that even if the dynamic data changed (here validEmail), Meteor Subscription was unaffected and did not change its data on UI? Is there any flag or something that triggers when subscription data is unchanged?

Upvotes: 1

Views: 80

Answers (1)

Jankapunkt
Jankapunkt

Reputation: 8413

Autorun, ReactiveVar and Subscriptions

In your code example the subscription itself will re-run the server's publication function as the subscription's input variable email depends on the reactive variable validEmail and thus triggers the autorun when validEmail changes.

You can easily check that on your server console by logging something to the console within the publication.

If validEmail remains unchanged than there is no reason for autorun to trigger (unless there are other reactive sources that may not be added to your code example).


What about the subscribed data

Now if something has caused the subscription to re-run and you want to know if the data of a collection has been changed you could easily check on collection.count() but this could be flawed.

Imagine your publication is parameterized to include different fields by different parameters, then the data that is transfered to the client side collection will be different.

You would then require a method to check on the client side collection's data integrity.


Use hashes to verify integrity

A possible help would be to generate hases from the dataset using the sha package.

You could for example create one hash of your whole collection:

// get data
const data = Collection.find().fetch();

// map data to strings
// and reduce to one string
const hashInput = data.map(doc => JSON.stringify(doc) ).reduce((a, b) => a + b);

// generate hash
const collectionHash = SHA256(hashInput);

After the next onReady you can generate a new hash of the collection and compare it with the previous hash. If they are different, then something has changed.

This also removes the need for iterating the collection's documents if you only want to know if the data has changed but it won't reveal which document has changed.


Hashing single documents

Hashing single documents gives you more insight about what has changed. To do that you only need to create a map of hashes of your collection:

// get data
const data = Collection.find().fetch();

// map data to strings
const hashes = data.map(doc => { _id: doc._id, hash: SHA256( JSON.stringify(doc) ) });

You can store these hashes together with a document's _id. If the hash of a document is different after a new subscription you can assume that the change is related to this document.

General notes

  • hashing is some kind of expensive operation so it might be difficult to keep up with performance on large collections
  • usually you should design your pub / sub and autorun in a way that when the input changes the output changes
  • code is cold-written so it may not work out of the box. Please let me know if something does not.

Upvotes: 1

Related Questions