So, here is my problem:
I have two Schemas on my MongoDB and I need to show a list of one of them, but including info of the other one. Here are my Schemas:
Ingredient = new SimpleSchema({
componentId: {
type: String
},
unit: {
type: String
},
amount: {
type: Number
}
});
RecipeSchema = new SimpleSchema({
name: {
type: String,
label: "Name"
},
desc: {
type: String,
label: "Description",
optional: true
},
ingredients: {
type: [Ingredient]
},
author: {
type: String,
label: "Author",
autoValue: function() {
return this.userId
},
autoform: {
type: "hidden",
label: false
}
},
createdAt: {
type: Date,
label: "Created At",
autoValue: function() {
return new Date()
},
autoform: {
type: "hidden",
label: false
}
}
});
On the Ingredient Schema, you will notice that the first field is actually componentId, which should match with another collection from the DB called Components. On this Components collection, I have the ID field and a name of the component, which should match with the ingredient inside the recipe.
How do I create a Publish of the recipes, showing the name of the ingredient/component instead of the ID? (I could use native way or cottz:publish-relations package, but I haven’t had success with any of them).
I just tried this one. I made a publish like this on the server:
Meteor.publishComposite('topTenRecipes', {
find: function() {
// Find top ten
return Recipes.find({}, { sort: { name: 1 }, limit: 10 });
},
children: [
{
find: function(recipe) {
// 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: recipe.authorId },
{ limit: 1, fields: { profile: 1 } });
}
},
{
find: function(recipe) {
// Find ingredients on recipe
return Components.find(
{ _id: recipe.componentId },
{ sort: { name: 1 } });
}
}
]
});
The list of recipes is still working, and there is no error. I changed also the {{componentId}} to {{name}} to show the ingredient name, but still doesn’t show.
I don’t actually know how to move on from here to show the name of the ingredients instead of the IDs.
Try modifying your Components
query:
return Components.find(
{ _id: { $in: recipe.componentId } },
{ sort: { name: 1 } });
}
Thanks for the answers, Rob!
I actually did like this:
return Components.find(
{ _id: { $in: recipe.ingredients.componentId } },
{ sort: { name: 1 } }
);
Because inside my recipe there is this array with the ingredients. Both ways, mine and yours, there was a big error on the terminal, but the understandable part was:
Exception in queued task: TypeError: Cannot read property ‘componentId’ of undefined
Any suggestions?
I made some progress here. I stopped using any packages to do the join and I’m doing all in pure Meteor.
The thing is: I managed how to do the join for example of userId to Meteor.users for example, but my previous problem still persist.
I don’t know how to structure the code to join an array inside a schema to another table. For example: I have recipes with ingredients inside it, but the ingredients are actually inside another table, and I only have the ID of each of those in an array inside the Recipe Schema. So what I have so far is the Schema that I sent on the first post in this thread, and this code:
Meteor.publish('recipes', function(){
return Recipes.find({ });
});
Meteor.publish('recipeDetails', function(id){
check(id, String);
return Recipes.find({ author: this.userId, _id: id });
});
and
Template.Recipes.onCreated(function() {
var self = this;
self.autorun(function() {
self.subscribe('recipes');
});
});
Template.Recipes.helpers({
recipes: function() {
return Recipes.find();
}
});
Template.RecipeItem.onCreated(function() {
this.editMode = new ReactiveVar(false);
});
Template.RecipeItem.helpers({
author: function() {
return Meteor.users.findOne(this.author);
},
updateRecipeId: function() {
return this._id;
},
editMode: function() {
return Template.instance().editMode.get();
}
});
and then the template:
<template name="Recipes">
{{#if $.Session.get 'newRecipe'}}
{{> NewRecipe}}
{{else}}
<button class="add-recipe">New Recipe</button>
{{/if}}
<section class="recipes">
{{#if Template.subscriptionsReady}}
{{#each recipes}}
{{> RecipeItem}}
{{else}}
<p>Please add a recipe.</p>
{{/each}}
{{else}}
<p>Loading</p>
{{/if}}
</section>
</template>
<template name="RecipeItem">
<article class="recipe-item">
<h3>{{name}}</h3>
<p>Author: {{author.profile.firstName}} {{author.profile.lastName}}</p>
<ul>
{{#each ingredients}}
<li>{{name}} - {{amount}}</li>
{{/each}}
</ul>
<a href="/recipe/{{_id}}">View Details</a>
<a href="" class="trash">Delete</a>
<a href="" class="pencil">Edit</a>
{{#if editMode}}
{{> quickForm collection="Recipes" id=updateRecipeId type="update" doc=this autosave=true}}
{{/if}}
</article>
</template>
So right now the {{name}} inside the ingredients, is blank, because I only have the componentId inside the array. Anybody?