我正在创建一个食谱数据库(通常称为食谱),我需要在成分和食谱之间建立多对多关系,并且我使用sequelize.js组合与postgresql。
当一种成分添加到配方中时,我需要声明配方中正确含量的成分。
我已宣布(缩减示例)
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'
});
我的问题是当我的一个REST端点执行
时如何返回数据router.get('/recipes', function(req, res) {
Recipe.findAll({
include: [{
model: Ingredient,
as: 'ingredients'
}]
}).then(function(r) {
return res.status(200).json(r[0].toJSON());
})
});
发送到客户端的结果JSON如下所示(省略时间戳):
{
"id": 1,
"name": "Carrots",
"ingredients": [
{
"id": 1,
"name": "carrot",
"RecipeIngredient": {
"amount": 12,
"RecipeId": 1,
"IngredientId": 1
}
}
]
}
虽然我想要的只是
{
"id": 1,
"name": "Carrots",
"ingredients": [
{
"id": 1,
"name": "carrot",
"amount": 12,
}
]
}
也就是说,我希望关系表中的amount
字段包含在结果中而不是整个RecipeIngredient
对象中。
sequelize生成的数据库如下所示:
Ingredients id name 1 carrot Recipes id name 1 Carrots RecipeIngredients amount RecipeId IngredientId 12 1 1
我尝试将attributes
数组作为属性提供给include
,如下所示:
include: [{
model: Ingredient,
as: 'ingredients',
attributes: []
}]
但是将['amount']
或['RecipeIngredient.amount']
设置为属性值会引发错误,例如
未处理拒绝SequelizeDatabaseError:列成分.RecipeIngredient.amount不存在
显然我可以使用.map
在JS中修复此问题,但肯定有办法让sequelize为我做这项工作吗?
答案 0 :(得分:1)
您可以使用sequelize.literal。使用Recipe的Ingredient别名,您可以编写如下。我不知道这是不是正确的方法。 :)
[sequelize.literal('`TheAlias->RecipeIngredient`.amount'), 'amount'],
我用sqlite3测试过。收到别名" ir"的结果是
{ 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] } ] }
请参阅此处的完整代码。
答案 1 :(得分:0)
我已经浏览了文档,但我找不到任何似乎可以让我将连接表的属性合并到结果中的内容,所以看起来我似乎陷入困境做这样的事情:
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);
});
});
将through
传递给include
让我可以过滤掉我想要包含在连接表中的属性,但是对于我的生活,我找不到让sequelize为我合并的方法。
上面的代码将返回我想要的输出,但是增加了循环遍历成分列表的开销,这不是我想要的,但除非有人提出更好的解决方案,否则我无法看到另一种方式这样做。
答案 2 :(得分:0)
我对此很晚,但是我看到它已经被浏览了很多,所以这是我关于如何合并的答案 属性
这是一些随机的例子
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)
})