Skip to content

Instantly share code, notes, and snippets.

@LeCoupa
Last active February 27, 2020 05:53
Show Gist options
  • Save LeCoupa/10951713 to your computer and use it in GitHub Desktop.
Save LeCoupa/10951713 to your computer and use it in GitHub Desktop.
Meteor: Reactive and Nonreactive Join with MongoDB --> https://github.com/LeCoupa/awesome-cheatsheets
<!--
The examples below illustrate different ways to make a reactive and nonreactive join between two collections.
We will retrieve in all of them a list of the 10 most popular posts along with their author profile.
More informations are available on: http://journal.gentlenode.com/
Summary:
1. Nonreactive Join #1: Denormalization.
2. Reactive Join #1: Joining on the client. (by calling a publication)
3. Reactive Join #2: Overpublishing. (and joining with data context)
4. Reactive Join #3: Using a package to make your publications reactive. (be careful about scalability)
-->
<!-- 1. Nonreactive Join #1: Denormalization. -->
<template name="PostList">
{{#each posts}}
<h1>{{title}}</h1>
<h2>{{author}}</h2>
{{/each}}}
</template>
<!-- 2. Reactive Join #1: Joining on the client. (by calling a publication) -->
<template name="PostList">
{{#each posts}}
<h1>{{title}}</h1>
<h2>{{author}}</h2>
{{/each}}
</template>
<!-- 3. Reactive Join #2: Overpublishing. (and joining with data context) -->
<template name="PostList">
{{#each posts}}
<h1>{{title}}</h1>
{{#with joinWithAuthor}}
<h2>{{author}}</h2>
{{/with}}
{{/each}}
</template>
<!-- 4. Reactive Join #3: Using a package to make your publications reactive. (be careful about scalability) -->
<template name="PostList">
{{#each posts}}
<h1>{{title}}</h1>
<h2>{{author}}</h2>
{{/each}}
</template>
// 1. Nonreactive Join #1: Denormalization.
// The concept is to denormalize data when you can.
// This avoids the need for joins but you need to take care about keeping your data up to date.
// This solution can be interesting for scaling your application in situations where the denormalized data do not change very much.
// e.g: Post document: { _id: "DdCroCRuXCvNq5vRc", title: "Meteor is Awesome", author: "LeCoupa" }
if (Meteor.isServer) {
Meteor.publish('getPopularPosts', function() {
return Posts.find({ }, { sort: { score: -1 }, limit: 10 };
});
}
if (Meteor.isClient) {
Template.PostList.created = function() {
Meteor.subscribe('getPopularPosts');
}
Template.PostList.helpers({
'posts': function() {
Posts.find();
}
})
}
// 2. Reactive Join #1: Joining on the client. (by calling a publication)
// We will only publish the post collection to the client.
// When the post needs to be displayed, we call a server-side method to grab the author informations.
// e.g: Post document: { _id: "DdCroCRuXCvNq5vRc", title: "Meteor is Awesome", userId: "5rNbbGpKDMSiBXF9h" }
// Author document: { _id: "5rNbbGpKDMSiBXF9h", author: "LeCoupa" }
if (Meteor.isServer) {
Meteor.publish('getPopularPosts', function() {
return Posts.find({ }, { sort: { score: -1 }, limit: 10 };
});
Meteor.publish('getAuthor', function(userId) {
check(userId, Number);
return Meteor.users.findOne(userId);
});
}
if (Meteor.isClient) {
Template.PostList.created = function() {
Meteor.subscribe('getPopularPosts');
}
Template.PostList.helpers({
'posts': function() {
Posts.find({ }, {
transform: function(doc) {
Meteor.subscribe('getAuthor', doc.userId);
}
});
}
'author': function() {
return Meteor.users.findOne(this.userId);
}
});
}
// 3. Reactive Join #2: Overpublishing. (and joining with data context)
// Sometimes, to avoid to deal with joins, you can decide in a certain situation to publish all the collection documents.
// Of course you need to make sure that this will not cause scalability problems inside your application.
// e.g: Post document: { _id: "DdCroCRuXCvNq5vRc", title: "Meteor is Awesome", userId: "5rNbbGpKDMSiBXF9h" }
// Author document: { _id: "5rNbbGpKDMSiBXF9h", author: "LeCoupa" }
if (Meteor.isServer) {
Meteor.publish('getPopularPosts', function() {
return Posts.find({ }, { sort: { score: -1 }, limit: 10 };
});
Meteor.publish('getEveryAuthors', function() {
return Meteor.users.find({ }, { fields: { username: 1 }}));
});
}
if (Meteor.isClient) {
Template.PostList.created = function() {
Meteor.subscribe('getPopularPosts');
Meteor.subscribe('getEveryAuthors');
}
Template.PostList.helpers({
'posts': function() {
Posts.find();
}
'joinWithAuthor': function() {
var post = this;
var author = Meteor.users.findOne(this.userId).username;
return _.extend(post, _.omit(author, '_id'));
}
});
}
// 4. Reactive Join #3: Using a package to make your publications reactive. (be careful about scalability)
// The reactive-publish package enables reactiviy within Meteor.publish functions.
// This causes the entire publication to re-run whenever any of its dependencies change.
// Just replace calls to "Meteor.publish" with "Meteor.reactivePublish".
// Atmosphere: https://atmospherejs.com/package/reactive-publish
// e.g: Post document: { _id: "DdCroCRuXCvNq5vRc", title: "Meteor is Awesome", userId: "5rNbbGpKDMSiBXF9h" }
// Author document: { _id: "5rNbbGpKDMSiBXF9h", author: "LeCoupa" }
if (Meteor.isServer) {
Meteor.reactivePublish('getPopularPostsAndAuthors', function() {
var posts = Posts.find({ }, { sort: { score: -1 }, limit: 10 };
var userIds = posts.map(function(doc) { return doc.userId });
var authors = Meteor.users.find({_id: {$in: userIds}}
return [ posts, authors ];
});
}
if (Meteor.isClient) {
Template.PostList.created = function() {
Meteor.subscribe('getPopularPostsAndAuthors');
}
Template.PostList.helpers({
'posts': function() {
return Posts.find();
}
'author': function() {
return Meteor.users.findOne(this.userId)
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment