Reputation: 512
I'm new to Meteor, building my first app. It's a cocktail-recipe app, with a collection of drinks and a collection of ingredients.
Each drink can have many ingredients. For each ingredient in a drink, there will be a quantity (number) and a unit of measure (string).
I vaguely suspect that, for this use case, something like the publish-with-relations package may be overkill, but I'm not clear on the best way to create and populate the third collection that would house this relationship between drinks and ingredients.
Here's what my drinks collection looks like:
Drinks = new Mongo.Collection('drinks');
Drinks.allow({
update: function(userId, drink) { return ownsDocument(userId, drink); },
remove: function(userId, drink) { return ownsDocument(userId, drink); }
});
Drinks.deny({
update: function(userId, drink, fieldNames) {
//only allow editing these fields:
return (_.without(fieldNames, 'drinkName', 'drinkIngredients').length > 0);
}
});
Meteor.methods({
drinkInsert: function(drinkAttributes) {
check(Meteor.userId(), String);
check(drinkAttributes, {
drinkName: String,
drinkIngredients: Array,
drinkDescription: String,
drinkInstructions: String
});
var errors = validateDrink(drinkAttributes);
if (errors.drinkName || errors.drinkIngredients)
throw new Meteor.Error('invalid-drink', "You must enter a drink name and ingredients.");
var drinkWithSameName = Drinks.findOne({drinkName: drinkAttributes.drinkName});
if (drinkWithSameName) {
return {
drinkExists: true,
_id: drinkWithSameName._id
}
}
var user = Meteor.user();
var drink = _.extend(drinkAttributes, {
userId: user._id,
author: user.username,
submitted: new Date(),
commentsCount: 0,
upvoters: [],
votes: 0
});
var drinkId = Drinks.insert(drink);
return {
_id: drinkId
};
},
upvote: function(drinkId) {
check(this.userId, String);
check(drinkId, String);
var affected = Drinks.update({
_id: drinkId,
upvoters: {$ne: this.userId}
}, {
$addToSet: {upvoters: this.userId},
$inc: {votes: 1}
});
if (! affected)
throw new Meteor.Error('invalid', "Vote not counted.");
}
});
validateDrink = function (drink) {
var errors = {};
if (!drink.drinkName)
errors.drinkName = "Please name your drink.";
if (!drink.drinkIngredients)
errors.drinkIngredients = "Please add some ingredients.";
if (!drink.drinkDescription)
errors.drinkDescription = "Please write a brief description of your drink.";
if (!drink.drinkInstructions)
errors.drinkInstructions = "Please include step-by-step instructions for mixing this drink.";
return errors;
}
Here's my ingredients collection:
Ingredients = new Mongo.Collection('ingredients');
Meteor.methods({
ingredientInsert: function(ingredientAttributes) {
check(this.userId, String);
check(ingredientAttributes, {
ingredientName: String
});
var user = Meteor.user();
ingredient = _.extend(ingredientAttributes, {
userId: user._id,
author: user.username,
submitted: new Date()
});
//create the ingredient, save the id
ingredient._id = Ingredients.insert(ingredient);
return ingredient._id;
}
});
My thinking is that the relationship should live in a collection called drinkIngredients, but I'm not clear on the best way to set up that collection in Meteor. I'd appreciate some guidance on this. Or, if I'm just making things harder on myself by not just using publish-with-relations, please let me know.
Thanks very much.
Upvotes: 0
Views: 230
Reputation: 64342
Unfortunately, adding more collections won't help unless you do something really redundant like denormalize both collections into a single set of documents. My advice is to choose one of the paths described here.
Note that in your case, you can't actually use PWR because it doesn't reactively join through arrays. I'd recommend using the "joining on the client" technique. This is the same pattern we currently follow at Edthena - join on the server with PWR when possible, but join on the client (using the router) when there's an array relationship.
For more details also see these related questions:
Upvotes: 2