[Publish / subscribe] client side's received data gets all records instead of filtered in publish callback

env

Meteor 1.6.1.1
uname -a
Darwin mac.local 16.7.0 Darwin Kernel Version 16.7.0: Mon Nov 13 21:56:25 PST 2017; root:xnu-3789.72.11~1/RELEASE_X86_64 x86_64

situation

I may not be clear about how meteor’s pub/sub works, but here is how I understand it.

  1. server publishes a cursor on a collection
  2. client side subscribe to the publish
  3. client gets the published data up to date

so if your publish is something like this, you get all products that are only on sale in your client side mini-mongo database.

if (Meteor.isServer) {
  Meteor.publish("products.onsale", function() {
    return Products.find({
      onSale: true
    })
  })
}

on client side

withTracker(() => {
  const subscription = Meteor.subscribe("products.onsale")
  const productsOnSale = Products.find().fetch()
  const loading = !subscription.ready()

  return {
    subscription,
    productsOnSale,
    loading
  }
})(Component)

problem

When I get the data, however, what I am experiencing for this case above, I get all products, either onSale true OR false, at the line const productsOnSale = Products.find().fetch() in the client side code.

Is there anything I am missing to get correct filtered data from the publish?

It turns out I had another subscribe, with a different publish name, on the same collection.


withTracker(() => {
  const subscription = Meteor.subscribe("products.onsale")
  const productsOnSale = Products.find().fetch()
  const loading = !subscription.ready()

  return {
    subscription,
    productsOnSale,
    loading
  }
})(Component)


// this one is located in another component that shows on the same page.
withTracker(() => {
  const subscription = Meteor.subscribe("products.all.availables")
  const productsOnSale = Products.find().fetch()
  const loading = !subscription.ready()

  return {
    subscription,
    productsOnSale,
    loading
  }
})(Component)

Since

const subscription = Meteor.subscribe("products.all.availables")

also runs at a different level on the same page, when I am to fetch

const subscription = Meteor.subscribe("products.onsale")
(expects ones only on sale)

returns something they are not.

How would you avoid a case like this?

This is normal behaviour for Meteor’s pub/sub. The client gets a merged set of all currently active publications. The way to mitigate this is to repeat the publication’s selection criteria in the find on the client.

Note also, that even if subscriptions are stopped and replaced by subscriptions with different selection criteria, there will be an overlap time when old and new documents are present on the client.

So, long story short, it’s always best to duplicate the server query/queries on the client.

2 Likes