Ad

Publish/subscribe Meteor Returns A Whole Collection

- 1 answer

I am implementing a publish/subscribe architecture for my Meteor app. I have not removed autopublish yet. I use React and kadira:flow-router with kadira:react-layout. It works fine.

This is my publish code (/lib/publications.js though I tried with /server/publications.js as well, no change):

if (Meteor.isServer) {
    Meteor.publish("games", function() {
        return Games.find({});
    });

    Meteor.publish("game", function(gameId) {
        return Games.find({_id: gameId});
    });

    Meteor.publish("messages", function(gameId) {
        return Messages.find({gameId: gameId}, {sort: {createdAt: -1}});
    });
}

Of course if I use it in /server I don't add the if statement. I subscribe to those publications in the router like this (/lib/routing.js):

user.route('/game/:id', {
    name: 'game',
    subscriptions: function(params, queryParams) {
        this.register('messages', Meteor.subscribe('messages', params.id));
    },
// ...
});

And then I get data in the React component like so (/client/components/pages/game_page.jsx):

// ...
mixins: [ReactMeteorData],
getMeteorData: function() {
    return {
        messages: Messages.find({}).fetch()
    }
},
// ...

Instead of getting all messages that have gameId equal to the passed argument I get ALL of the messages from ALL of the games. If I remove the publish/subscribe and just ask for data like this:

// ...
mixins: [ReactMeteorData],
getMeteorData: function() {
    return {
        messages: Messages.find({gameId: gameId}, {sort: {createdAt: -1}}).fetch()
    }
},
// ...

It works perfectly fine. Any idea why? I think I am missing something: either about publish/subscribe itself or about using subscribe in router.

Ad

Answer

Autopublish package publishes all data to client (it is like you subscribed to a publication that does Collection.find({}) on all collections). It means, that your custom publication/subscribtion actually does nothing in your example, and if you query data like this:

getMeteorData: function() {
    return {
        messages: Messages.find({}).fetch()
    }
},

you will just get all messages, and that's correct behavior.

Anyway, you should always make the explicit query in data query like this:

getMeteorData: function() {
    return {
        messages: Messages.find({gameId: gameId}, {sort: {createdAt: -1}}).fetch()
    }
},

because if you happen to have two different messages subscriptions at the same time (for different purposes, i.e. one subscription for one message with all details and another for different messages with less details/fields), this data query Messages.find({}) will get you union of the documents subscribed in both subscriptions, and it probably won't be what you would expect.

So, in your case, remove autopublish package, and add this explicit query in data access (messages: Messages.find({gameId: gameId}, {sort: {createdAt: -1}}).fetch()).

Ad
source: stackoverflow.com
Ad