What's the right way to do multiple subscriptions to the same collection?


#1

Let’s say I have a blog app, and in the collection it has “title”, “body”, “pic”, “summary”.

On the main page I want to have it show just the “title” and “summary”, and then when you click on one you want to read it shows “title”, “body”, and “pic”.

I obviously only need to publish parts of the blog post depending on the view, and that would benefit performance I’m guessing.

But this doesn’t work as I would expect:

    Meteor.publish('postList', function() {
        return Posts.find({}, {fields: {"title":1, "summary":1}})
    })
Meteor.publish('postDetail', function() {
        return Posts.find({}, {fields: {"summary":0}})
    })

My post list still seems to have access to the “body” and “pic” when I just want it to get the “title” and “summary”. Now obviously it’s because on my post list template I still have {{body}}, and I could delete that, but it still means it’s being published and accessible even when I don’t subscribe to it.

So is it working correct and I’m just using it wrong or do I have something wrong with how I’m doing publications and subscriptions?


#2

If you want the postDetail data to go away, you need to stop the postDetail subscription. Did you do that?


#3

Hey @erikbigelow this might be an issue with how you are reasoning about the projection which is the fields : {title: 1} section.

in the mongodb docs it explains the projection concept a bit more;
http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/

What is happening when you subscribe to postList it is returning with an inclusion projection which will include ONLY title and summary (& _id, but that is usually included by default).

However when you then also subscribe to postDetail you are then doing a suppression projection, this essentially sets it to only hide summary but SEND all other fields, so that is why you are getting ‘title’ and all other fields on the Posts documents, all expect summary.

I am not sure how Meteor reasons about conflicting projections (that could be an issue if you are accidentally subscribing to both at once), but a better approach from my experience is always to be explicit about what you want (good habit as it saves you data on the wire and forces you to think about what you want to send every time).

This means only using inclusion projections, and would change your publications to:
Meteor.publish('postList', function() { return Posts.find({}, {fields: {"title":1, "summary":1}}) }) Meteor.publish('postDetail', function() { return Posts.find({}, {fields: {"title":1, "body": 1, "pic": 1}}) })
This way summary will NOT show when postDetail is being subscribed to.

Another note that mongo (as per the docs linked above) does not let you put inclusion and suppression projections in the same query.

Summary

  • Projection: Definition of what fields to return in the query, and can be one of two types;
  • Inclusion: A projection that defines the ONLY fields to return.
  • Suppression: A projection that defines the only fields NOT to return.
  • You cannot combine inclusion and exclusion semantics in a single projection with the exception of the _id field.

#4

This is great info and thanks for the link! I think I understand it now.