I have the following model:
#order/model.coffee
Order = DS.Model.extend {
line_items: DS.hasMany 'product', {async: true}
}
At some point I want to add the some products to the order. I found that I can only add the product once, adding the same product again does not work:
#product/route.coffee
...
actions:
# Not actually my code but illustrates the problem
addToCart: (product1, product2)->
order = #modelFor 'order'
console.log order.get('line_items.length') # prints 0
order.get('line_items').pushObject product1
console.log order.get('line_items.length') # prints 1
order.get('line_items').pushObject product2
console.log order.get('line_items.length') # prints 2
order.get('line_items').pushObject product1
console.log order.get('line_items.length') # prints 2
order.get('line_items').pushObject product2
console.log order.get('line_items.length') # prints 2
...
The problem is that the user might want a single item more than once. The simplest way to represent that is to have an array with duplicate entries. It seems Ember is not letting me do that for relationships. How can I add a model more than once to a relationship ?
It sounds like you actually need a line_items model with a quantity field. Just shoving more of the same item in your orders model isn't really a normalized solution.
I would recommend the following:
lineItem = DS.Model.extend({
orders: DS.belongsTo('orders'),
product: DS.belongsTo('products'),
quantity: DS.attr('number'),
});
orders = DS.Model.extend({
lineItems: DS.hasMany('lineItem', {async: true}),
customerId: DS.belongsTo('customers'),
});
products = DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
cost: DS.attr('string'),
});
This would allow you to create multiple records in your lineItem model, that will have a unique ID but be bound to a specific order, (which would solve the issue of multiple orders having the same lineItem) for example, you could have:
{
"lineItem" :
[
{
"id": 1,
"orderId": 1,
"product": 1,
"quantity": 100,
},
{
"id": 2,
"orderId": 1,
"product": 2,
"quantity": 10,
},
{
"id": 3,
"orderId": 2,
"product": 1,
"quantity": 100,
}
]
}
In this design you would remove the reference to lineItems from your json, as ember-data looks after the inverse relationship for you (if you aren't sideloading the relationship you will need to add async to your model). This will mean that if you need to change a line item, it will only affect one order, and if you need to change the order that a lineItem is related to you just do this on the lineItem model.
{
"Orders" :
[
{
"id": 1,
"customerId": 123456,
},
{
"id": 2,
"customerId": 123456,
}
]
}
They should have an id property, then they will be able to co-exist in the same array and be distinct items of the same product type - with the same name (all the same properties other than id).
Either that, or you have one record that represents a product type, and then have a quantity attribute to specify how many of each product there are..
Related
Objective
To have an efficient search using references in MongoDB.
Background
I have a Smoothie DB on Mongo. A smoothie is an object with a reference to a Food object and it is represented like:
{
name: "Red Velvet Cake",
ingredients: [{
food_id: "strawberry_raw",
//other really cool fields
},
//other ingredients
],
preparation: "Mix everything and have fun!",
Source: "Super Smoothies, p. 142"
}
Now, a Food object is represented by the following example:
{
"_id": "strawberry_raw",
"name": "strawberries",
//other really cool fields
}
Problem
With these schemas in mind, I am making sure that a Smoothie object knows all the Food objects that build it. Since each Smoothie object will have at most 6 or 7 food objects, I believe this is the best choice as it follows the MongoDB's Principle of least Cardinality.
However, now I want to allow the following functionalities:
Given a list of ingredient names, return all smoothies that contain at least one of those ingredients
Given a list of ingredient names, return only the smoothies that contain all those ingredients.
And I have no idea how to do it with MongdoDB.
Example
The following examples illustrate what I want.
Imagine I have the following Foods:
let foods = [{
"_id": "strawberry_raw",
"name": "strawberries"
}, {
"_id": "honeydew_melon_raw",
"name": "honeydew melon"
}, {
"_id": "coconut_milk",
"name": "homemade coconut milk"
}];
And the following Smoothies:
let smoothies = [
{
name: "Coco Berry",
ingredients: [
{ food_id: "strawberry_raw" },
{ food_id: "coconut_milk"}
],
preparation: "Mix everything and have fun!",
Source: "Super Smoothies, p. 142"
},
{
name: "Tropical Melon",
ingredients: [
{ food_id: "honeydew_melon_raw"},
{ food_id: "coconut_milk"}
],
preparation: "Mix everything and have fun!",
Source: "Super Smoothies, p. 51"
}];
Given a search with the term "coconuts, strawberry", the functionalities would return:
Coco Berry and Tropical Melon, as both smoothie have at least one of the ingredients (coconut milk)
Coco Berry, as this smoothie has both ingredients, and the second one is missing one ingredient.
What I tried and what i need
I know that to turn a search like "coconuts" return a Food with name "Coconut Milk" I have to index the names in the Food collection, which I did.
I also searched and I found that I will likely need to use $lookup, however, I don't know how to move from that point forward. How do I do it ?
I think there is no need of adding a join or index you can use $regex,let me try my hand,consider smothie as your collection
`
db.collection.find({ingredients : {$elemMatch : {$or :[
{food_id : {$regex : "coconuts")},{food_id : {$regex : "strawberry")}]}}})
`
Your second query
`
db.collection.find({ingredients : {$elemMatch : {$and :[
{food_id : {$regex : "coconuts")},{food_id : {$regex : "strawberry")}]}}})
`
I'm trying to figure out the best way for my Redux Store to handle lists. Right now it looks like this:
Store = {
users: [],
posts: [],
lists: [],
}
My problem with this, is the list array. Essentially it's a store for paginated lists of a specific resource, so for example:
lists: [
{
id: 'users/43/posts',
items: [25, 36, 21]
}
]
Since I am using the url as the id, my component that shows a user's list of posts will know exactly which list to display. Now someone has told me that, this is a very very bad idea. And I just want some advice on what could be better. Another approach suggested was this:
users: [{
id: 2,
posts: [
{
url: 'users/2/posts',
items: [13, 52, 26],
}
]
}]
So what I don't understand, how does Redux know where to save this list? Do I have to specify in the action arguments where to save it?
Thank you for your advice.
Well, technically, anything works if you make it work! The second approach looks more mature, though. You don't want to use URLs as ID. IDs should be numbers or special sequence of characters+numbers. When your application grows, you'll want to normalize your data i.e. store the IDs in a separate array and transform the array of objects into an object with keys as ID.
Example from Normalizr
[{
id: 1,
title: 'Some Article',
author: {
id: 1,
name: 'Dan'
}
}, {
id: 2,
title: 'Other Article',
author: {
id: 1,
name: 'Dan'
}
}]
can be normalized to -
{
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
}
}
}
When your application grows, you'll have multiple reducers and sub-reducers. You'll want to slice a specific portion of your state-tree and so on. For that reason someone might have advised you to store your state in a different manner.
But again, anything works if you make it work! Good luck!
I'm creating a recipe-database (commonly known as a cookbook) where I need to have a many-to-many relationship between ingredients and recipes and I'm using sequelize.js in combination with postgresql.
When an ingredient is added to a recipe I need to declare the correct amount of that ingredient that goes into the recipe.
I've declared (reduced example)
var Ingredient = sequelize.define('Ingredient', {
name: Sequelize.STRING
}, {
freezeTable: true
});
var Recipe = sequelize.define('Recipe', {
name: Sequelize.STRING
}, {
freezeTable: true
});
var RecipeIngredient = sequelize.define('RecipeIngredient', {
amount: Sequelize.DOUBLE
});
Ingredient.belongsToMany(Recipe, { through: RecipeIngredient });
Recipe.belongsToMany(Ingredient, {
through: RecipeIngredient,
as: 'ingredients'
});
My problem is with how data is returned when one my REST endpoints do
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients'
}]
}).then(function(r) {
return res.status(200).json(r[0].toJSON());
})
});
The resulting JSON that gets sent to the client looks like this (timestamps omitted):
{
"id": 1,
"name": "Carrots",
"ingredients": [
{
"id": 1,
"name": "carrot",
"RecipeIngredient": {
"amount": 12,
"RecipeId": 1,
"IngredientId": 1
}
}
]
}
While all I wanted was
{
"id": 1,
"name": "Carrots",
"ingredients": [
{
"id": 1,
"name": "carrot",
"amount": 12,
}
]
}
That is, I want the amount field from the relation-table to be included in the result instead of the entire RecipeIngredient object.
The database generated by sequelize looks like this:
Ingredients
id name
1 carrot
Recipes
id name
1 Carrots
RecipeIngredients
amount RecipeId IngredientId
12 1 1
I've tried to provide an attributes array as a property to the include like this:
include: [{
model: Ingredient,
as: 'ingredients',
attributes: []
}]
But setting either ['amount'] or ['RecipeIngredient.amount'] as the attributes-value throws errors like
Unhandled rejection SequelizeDatabaseError: column ingredients.RecipeIngredient.amount does not exist
Obviously I can fix this in JS using .map but surely there must be a way to make sequelize do the work for me?
I am way late to this one, but i see it been viewed quite a bit so here is my answer on how to merge
attributes
Some random examples in this one
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients',
through: {
attributes: ['amount']
}
}]
})
.then(docs =>{
const response = {
Deal: docs.map(doc =>{
return{
cakeRecipe:doc.recipe1,
CokkieRecipe:doc.recipe2,
Apples:doc.ingredients.recipe1ingredient
spices:[
{
sugar:doc.ingredients.spice1,
salt:doc.ingredients.spice2
}
]
}
})
}
})
res.status(200).json(response)
})
You can use sequelize.literal. Using Ingredient alias of Recipe, you can write as follows. I do not know if this is the right way. :)
[sequelize.literal('`TheAlias->RecipeIngredient`.amount'), 'amount'],
I tested with sqlite3. Received result with alias "ir" is
{ id: 1,
name: 'Carrots',
created_at: 2018-03-18T04:00:54.478Z,
updated_at: 2018-03-18T04:00:54.478Z,
ir: [ { amount: 10, RecipeIngredient: [Object] } ] }
See the full code here.
https://github.com/eseom/sequelize-cookbook
I've gone over the documentation but I couldn't find anything that seems like it would let me merge the attributes of the join-table into the result so it looks like I'm stuck with doing something like this:
router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients',
through: {
attributes: ['amount']
}
}]
}).then(function(recipes) {
return recipes[0].toJSON();
}).then(function(recipe) {
recipe.ingredients = recipe.ingredients.map(function(i) {
i.amount = i.RecipeIngredient.amount;
delete i.RecipeIngredient;
return i;
});
return recipe;
}).then(function(recipe) {
return res.status(200).json(recipe);
});
});
Passing through to include lets me filter out which attributes I want to include from the join-table but for the life of me I could not find a way to make sequelize merge it for me.
The above code will return the output I wanted but with the added overhead of looping over the list of ingredients which is not quite what I wanted but unless someone comes up with a better solution I can't see another way of doing this.
New to angular! So two sets of data. One containing meals, one containing entries. Each meal can have several entries, but each entry only relates to one meal.
In my data, the meals table has an Id, and in the entries table, there is a reference to the meal id with a meal_id property.
meal:
{
id: 4,
user_id: 3,
date: 12345678,
name: "soFood",
location: "Litchfield, CT",
rating: 1,
notes: "This is a note here",
image: "http://www.image.com"
},
entry:
{
id: 3,
meal_id: 4,
name: "Fet UP",
rating: 0,
notes: null,
image: "http://not.anote.here"
}
At the moment I am able to repeat the meals. I'd like to be able to uniquely repeat the entries for an individual meal.
So for a list of meals, be able to click on one and have a list of its unique entries show up.
I know I have to somehow get the meal_id to compare to the id of the meals but I'm unsure how to use ng-repeat doing that?
You will first affect the current meal to a variable in your upper ng-repeat, i.e. ng-repeat="meal in meals". This current meal is known in the scope of the ng-repeat directive. You can use it to filter an entries array and use the result in an inner ng-repeat :
<li ng-repeat="meal in meals">
<div ng-repeat="entry in (entries | filter : {'meal_id': meal.id})">
</div>
</li>
I have two Ember JS models (in an Ember CLI application):
list
link
Each list can have multiple links and as a result, I've declared my list model as:
import DS from 'ember-data';
export default DS.Model.extend({
title : DS.attr('string'),
slug : DS.attr('string'),
visibility : DS.attr('string'),
owner : DS.attr('string'),
links : DS.hasMany('link')
});
This is what the link model looks like:
import DS from 'ember-data';
export default DS.Model.extend({
title : DS.attr('string'),
shortUrl: DS.attr('string'),
views : DS.attr('number'),
owner : DS.attr('string')
});
Within the list.js route, I make a call to fetch the list and its links like this:
model: function(params) {
// Get list properties and links
var list = this.store.find('list', params.listName);
return list;
},
The REST adapter correctly makes the call and my server returns the following response:
{
"lists": [
{
"title": "Design",
"slug": "design",
"visibility": "private",
"owner": "5540b2fb9611f67a07f7f6c1",
"id": "5565ae05ca217589bc2a1bdf",
"links": [
1,
2,
3
]
}
],
"links": [
{
"id": 1,
"title": "Dribbble - Show and tell for designers",
"shortUrl": "http://sl.fi/a1CRgc",
"views": 144,
"owner": "5540b2fb9611f67a07f7f6c1"
},
{
"id": 2,
"title": "Dribbble - Show and tell for designers",
"shortUrl": "http://sl.fi/a1CRgc",
"views": 144,
"owner": "5540b2fb9611f67a07f7f6c1"
},
{
"id": 3,
"title": "Dribbble - Show and tell for designers",
"shortUrl": "http://sl.fi/a1CRgc",
"views": 144,
"owner": "5540b2fb9611f67a07f7f6c1"
}
]
}
I modeled my response based on the Ember Data Model Maker. I have a list template that should loop through the links in the model so I am doing this:
{{#each links in model}}
<span>{{ links.title }}</span>
{{/each}}
I get the following error when I load my application and I just can't seem to figure out a solution:
Uncaught Error: Assertion Failed: The value that #each loops over must be an Array. You passed <web-app#model:list::ember388:5565ae05ca217589bc2a1bdf>
Can someone please help me with a solution?
links is a child relation to lists, the links array becomes a property on lists...
therefore your each helper should be:
{{#each link in model.links}}
also, you will want to start using the new syntax soon too.. (depending on your ember version):
{{#each model.links as |links|}}