Tomasz Gałkowski
Tomasz Gałkowski

Reputation: 1929

Publish/subscribe Meteor returns a whole Collection

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.

Upvotes: 1

Views: 368

Answers (2)

Paweł Jasiurkowski
Paweł Jasiurkowski

Reputation: 317

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()).

Upvotes: 1

Kamalpreet
Kamalpreet

Reputation: 1143

You'll have to remove the autopublish package because by default it publishes everything in the collection.

From my understanding, every subscription exposes some documents in the collection so if you had you have two subscriptions for the same collection then when you query your collection you will have access to all the documents that two subscriptions expose so it is accumulative.

Upvotes: 2

Related Questions