Search code examples
meteormeteor-blaze

How to display children of "publish-composite collection" on Template View


Considering the example given at https://github.com/englue/meteor-publish-composite

How to display nested children on the template view. I mean, displaying top 2 comments on the post on the view.

I have searched a lot over internet for this children tree display on Template View, didn't find any.

Code

publishComposite('topTenPosts', {
    find() {
        // Find top ten highest scoring posts
        return Posts.find({}, { sort: { score: -1 }, limit: 10 });
    },
    children: [
        {
            find(post) {
                // Find post author. Even though we only want to return
                // one record here, we use "find" instead of "findOne"
                // since this function should return a cursor.
                return Meteor.users.find(
                    { _id: post.authorId },
                    { fields: { profile: 1 } });
            }
        },
        {
            find(post) {
                // Find top two comments on post
                return Comments.find(
                    { postId: post._id },
                    { sort: { score: -1 }, limit: 2 });
            },
            children: [
                {
                    find(comment, post) {
                        // Find user that authored comment.
                        return Meteor.users.find(
                            { _id: comment.authorId },
                            { fields: { profile: 1 } });
                    }
                }
            ]
        }
    ]
});

Solution

  • Using Blaze it should just be a simple set of templates where you search for the related comments and authors in a helper, displaying the posts and comments with nested {{#each}} loops.

    html:

    <template name="posts">
    {{#each posts}}
      Title: {{title}} posted on: {{date}} by: {{authorName}}
      {{#each comments}}
        {{> comment}}
      {{/each}}
    {{/each}}
    </template>
    
    <template name="comment">
    Post comment {{body}} by {{authorName}} on {{createdAt}}
    </template>
    

    Now for the helpers:

    Template.posts.helpers({
      posts(){
        return Posts.find({}, { sort: { score: -1 }, limit: 10 });
      },
      comments(){
        return Comments.find({ postId: this._id },{ sort: { score: -1 }, limit: 2 });
      },
      authorName(){
        return Meteor.users.findOne(this.authorId).username;
    });
    
    Template.comment.helpers({
      authorName(){
        return Meteor.users.findOne(this.authorId).username;
      },
    });
    

    Note the use of this in these helpers. this will be the value of the data context at the point of evaluation. Inside the {{#each}} blocks this takes on the value of the current document, i.e. an object with keys.

    You can keep the authorName helpers DRY by creating a global helper if you like.