Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One to Many Relationship (or NoSQL Mongo equivalent to it) in Meteor Collections

I am new to Mongo and NoSQL databases. Can someone explain the way to do a one to many join and a cycling through collections in Meteor.

For example, say I have two collections, a Post and a Comment where each comment has a postId, meaning each Post has zero or many Comments. I am interested in what would be best practice for this type of situation for Meteor specifically where you can cycle through each post and comment in a nested Handlebars call. Something like the example below:

{{#each post}}
  {{title}}
  {{content}}
  {{#each comment}}
    {{comment_text}} by {{author}}
  {{/each}}
{{/each}}
like image 438
JAMESSTONEco Avatar asked Jan 06 '14 12:01

JAMESSTONEco


1 Answers

Although the standard MongoDB paradigm is to denormalize data, in Meteor applications it's not uncommon to stick to the pattern of having different collections (tables) for each logical dataset.

To implement joins in Meteor webapps, you simply have to define a relation between the two collections :

var postId = Posts.insert({
  title: "A post",
  content: "Some content..."
});

Comments.insert({
  postId: postId,
  author: "Someone",
  text: "Some text..."
});

Denormalizing means that you must not forget to publish the two collections, you can do as follow :

Meteor.publish("postById", function(postId){
  // publish the according post...
  var postCursor = Posts.find(postId);
  // ...and every comments associated
  var commentsCursor = Comments.find({
    postId: postId
  });
  // you can return multiple cursors from a single publication
  return [postCursor, commentsCursor];
});

This publication would send down to the client a post and all its comments, given a post._id. Associated with correct client-side routing, you can subscribe to this publication with the post id retrieved from a URL (/posts/:_id) and display the post with all its comments.

Your template pseudo code is OK, however I would refactor it using a distinct template for each collection.

HTML

<template name="outer">
  {{!-- loop through each post, the child template will
        be using the current post as data context --}}
  {{#each posts}}
      {{> post}}
  {{/each}}
</template>

JS

Template.outer.helpers({
  posts: function(){
    return Posts.find();
  }
});

HTML

<template name="post">
  <h3>{{title}}</h3>
  <p>{{content}}</p>
  {{!-- loop through each comment and render the associated template --}}
  {{#each comments}}
    {{> comment}}
  {{/each}}
</template>

JS

Template.posts.helpers({
  comments: function(){
    // return every comment belonging to this particular post
    // here this references the current data context which is
    // the current post being iterated over
    return Comments.find({
      postId: this._id
    });
  }
});

HTML

<template name="comment">
  <p>{{text}}</p>
  <span>by {{author}}</span>
</template>
like image 96
saimeunt Avatar answered Nov 15 '22 06:11

saimeunt