Neelesh
Neelesh

Reputation: 1478

Meteor publish method

I just started the Meteor js, and I'm struggling in its publish method. Below is one publish method.

//Server side

Meteor.publish('topPostsWithTopComments', function() {
  var topPostsCursor = Posts.find({}, {sort: {score: -1}, limit: 30});
  var userIds = topPostsCursor.map(function(p) { return p.userId });

  return [
    topPostsCursor,
    Meteor.users.find({'_id': {$in: userIds}})
  ];
});

// Client side

Meteor.subscribe('topPostsWithTopComments');

Now I'm not getting how I can use publish data on client. I meant I want to use data which will be given by topPostsWithTopComments

Problem is detailed below

When a new post enters the top 30 list, two things need to happen:

The server needs to send the new post to the client.
The server needs to send that post’s author to the client.

Meteor is observing the Posts cursor returned on line 6, and so will send the new post down as soon as it’s added, ensuring the client will receive the new post straight away.

However, consider the Meteor.users cursor returned on line 7. Even if the cursor itself is reactive, it’s now using an outdated value for the userIds array (which is a plain old non-reactive variable), which means its result set will be out of date as well.

This is why as far as that cursor is concerned, there is no need to re-run the query and Meteor will happily continue to publish the same 30 authors for the original 30 top posts ad infinitum.

So unless the whole code of the publication runs again (to construct a new list of userIds), the cursor is no longer going to return the correct information.

Basically what I need is:

if any changes happens in Post, then it should have the updated users list. without calling user collection again. I found some user full mrt modules. link1 | link2 | link3

Please share your views!

-Neelesh

Upvotes: 0

Views: 817

Answers (2)

Tobias
Tobias

Reputation: 4074

I think @Will Brock already answered your question but maybe it becomes more clear with an abstract example.

Let's construct two collections named collectiona and collectionb.

// server and client
CollectionA = new Meteor.Collection('collectiona');
CollectionB = new Meteor.Collection('collectionb');

On the server you could now call Meteor.publish with 'collectiona' and 'collectionb' separately to publish both record sets to the client. This way the client could then also separately subscribe to them.

But instead you can also publish multiple record sets in a single call to Meteor.publish by returning multiple cursors in an array. Just like in the standard publishing procedure you can of course define what is being sent down to the client. Like so:

if (Meteor.isServer) {
  Meteor.publish('collectionAandB', function() {
    // constrain records from 'collectiona': limit number of documents to one
    var onlyOneFromCollectionA = CollectionA.find({}, {limit: 1});

    // all cursors in the array are published
    return [
      onlyOneFromCollectionA,
      CollectionB.find()
    ];
  });
}

Now on the client there is no need to subscribe to 'collectiona' and 'collectionb' separately. Instead you can simply subscribe to 'collectionAandB':

if (Meteor.isClient) {
  Meteor.subscribe('collectionAandB', function () {
    // callback to use collection A and B on the client once 
    // they are ready

    // only one document of collection A will be available here
    console.log(CollectionA.find().fetch()); 

    // all documents from collection B will be available here
    console.log(CollectionB.find().fetch());
  });
}

So I think what you need to understand is that there is no array sent to the client that contains the two cursors published in the Meteor.publish call. This is because returning an array of cursors in the function passed as an argument to your call to Meteor.publish merely tells Meteor to publish all cursors contained in the array. You still need to query the individual records using your collection handles on the client (see @Will Brock's answer).

Upvotes: 0

Will Brock
Will Brock

Reputation: 95

When you publish data on the server you're just publishing what the client is allowed to query. This is for security. After you subscribe to your publication you still need to query what the publication returned.

if(Meteor.isClient) {
    Meteor.subscribe('topPostsWithTopComments');
    // This returns all the records published with topPostsWithComments from the Posts Collection
    var posts = Posts.find({});
}

If you wanted to only publish posts that the current user owns you would want to filter them out in the publish method on the server and not on the client.

Upvotes: 1

Related Questions