Knex SQL 在第一个 Table 上将多个其他 Table 加入数组
Knex SQL Join Multiple Other Tables into Array on First Table
目前我正在使用 Knex 查询 MSSQL 数据库。我有一个 table 这样的:
Meals
Id
Vegetables
Id
Meal
(参考膳食 table)
Fruits
Id
Meal
(参考膳食 table)
所以一个餐 ID 可以有多种蔬菜table或水果。我正在寻找一个包含所有蔬菜 table 的数组,结果中所有水果的数组的膳食 ID 的结果。现在使用 knex('meals').innerJoin('fruits', 'meals.id', 'fruits.meal')
,我得到了多个对象。
是的,您肯定会通过该查询获得多个对象。您没有指定要 SELECT
的内容,因此数据库 returns 一切。
整体架构可能不适合您(我假设)您想要实现的目标。您似乎想要类似这样的输出?
{
Id: 1,
Name: 'Spinach Pie',
Ingredients: [
{ Id: 1, Name: 'Spinach', Type: 'Vegetable' },
{ Id: 2, Name: 'Garlic', Type: 'Vegetable' }
]
}
在您当前的架构下,每种蔬菜table或水果只能搭配一顿饭。这是一个 HAS ONE 关系:"a vegetable has one meal"。显然,我们可以在各种不同的菜肴中使用任何给定的蔬菜table,因此我们需要以不同的方式思考问题。正确的思考方式是,一份蔬菜table有很多餐,一顿饭有很多蔬菜table。这将我们引向一个带有连接 table:
的结构
Meals
- Id
- Name
Ingredients
- Id
- Name
- Type
MealsIngredients
- Id
- Meal
- Ingredient
(我不一定会这样写一本真正的食谱书,但出于演示目的...)
这会给我们这样的查询:
knex('Meals')
.select('Meals.Name as mealName', 'Ingredients.*')
.innerJoin('MealsIngredients', 'Meals.Id', 'MealsIngredients.Meal')
.innerJoin('Ingredients', 'Ingredients.Id', 'MealsIngredients.Ingredient')
.where('Meals.Id', mealId)
它不会让你到达你想要的地方,但到目前为止:
[
{ mealName: 'Spinach Pie', Id: 1, Name: 'Spinach', Type: 'Vegetable' },
{ mealName: 'Spinach Pie', Id: 2, Name: 'Garlic', Type: 'Vegetable' }
]
要将其与用餐细节相结合,有多种选择。我们可以发出两个单独的查询,或某种数组聚合(我不太熟悉那里的 SQL 服务器选项)。考虑到这里的要求相对简单,你可能只是 assemble 你在 JS 中追求的对象:
const outputFormatter = (output, ingredient) => {
output.name = ingredient.mealName
if (!output.ingredients) {
output.ingredients = []
}
const { mealName, ...theIngredient } = ingredient
output.ingredients.push(...theIngredient)
return output
}
knex('Meals')
.select('Meals.Name as mealName', 'Ingredients.*')
.innerJoin('MealsIngredients', 'Meals.Id', 'MealsIngredients.Meal')
.innerJoin('Ingredients', 'Ingredients.Id', 'MealsIngredients.Ingredient')
.where('Meals.Id', mealId)
.then(records => records.reduce(outputFormatter, {}))
这将产生:
{
name: 'Spinach Pie',
ingredients: [
{ Id: 1, Name: 'Spinach', Type: 'Vegetable' },
{ Id: 2, Name: 'Garlic', Type: 'Vegetable' }
]
}
我可能在大写方面有些失误...我不习惯 PascalCase!
目前我正在使用 Knex 查询 MSSQL 数据库。我有一个 table 这样的:
Meals
Id
Vegetables
Id
Meal
(参考膳食 table)
Fruits
Id
Meal
(参考膳食 table)
所以一个餐 ID 可以有多种蔬菜table或水果。我正在寻找一个包含所有蔬菜 table 的数组,结果中所有水果的数组的膳食 ID 的结果。现在使用 knex('meals').innerJoin('fruits', 'meals.id', 'fruits.meal')
,我得到了多个对象。
是的,您肯定会通过该查询获得多个对象。您没有指定要 SELECT
的内容,因此数据库 returns 一切。
整体架构可能不适合您(我假设)您想要实现的目标。您似乎想要类似这样的输出?
{
Id: 1,
Name: 'Spinach Pie',
Ingredients: [
{ Id: 1, Name: 'Spinach', Type: 'Vegetable' },
{ Id: 2, Name: 'Garlic', Type: 'Vegetable' }
]
}
在您当前的架构下,每种蔬菜table或水果只能搭配一顿饭。这是一个 HAS ONE 关系:"a vegetable has one meal"。显然,我们可以在各种不同的菜肴中使用任何给定的蔬菜table,因此我们需要以不同的方式思考问题。正确的思考方式是,一份蔬菜table有很多餐,一顿饭有很多蔬菜table。这将我们引向一个带有连接 table:
的结构Meals
- Id
- Name
Ingredients
- Id
- Name
- Type
MealsIngredients
- Id
- Meal
- Ingredient
(我不一定会这样写一本真正的食谱书,但出于演示目的...)
这会给我们这样的查询:
knex('Meals')
.select('Meals.Name as mealName', 'Ingredients.*')
.innerJoin('MealsIngredients', 'Meals.Id', 'MealsIngredients.Meal')
.innerJoin('Ingredients', 'Ingredients.Id', 'MealsIngredients.Ingredient')
.where('Meals.Id', mealId)
它不会让你到达你想要的地方,但到目前为止:
[
{ mealName: 'Spinach Pie', Id: 1, Name: 'Spinach', Type: 'Vegetable' },
{ mealName: 'Spinach Pie', Id: 2, Name: 'Garlic', Type: 'Vegetable' }
]
要将其与用餐细节相结合,有多种选择。我们可以发出两个单独的查询,或某种数组聚合(我不太熟悉那里的 SQL 服务器选项)。考虑到这里的要求相对简单,你可能只是 assemble 你在 JS 中追求的对象:
const outputFormatter = (output, ingredient) => {
output.name = ingredient.mealName
if (!output.ingredients) {
output.ingredients = []
}
const { mealName, ...theIngredient } = ingredient
output.ingredients.push(...theIngredient)
return output
}
knex('Meals')
.select('Meals.Name as mealName', 'Ingredients.*')
.innerJoin('MealsIngredients', 'Meals.Id', 'MealsIngredients.Meal')
.innerJoin('Ingredients', 'Ingredients.Id', 'MealsIngredients.Ingredient')
.where('Meals.Id', mealId)
.then(records => records.reduce(outputFormatter, {}))
这将产生:
{
name: 'Spinach Pie',
ingredients: [
{ Id: 1, Name: 'Spinach', Type: 'Vegetable' },
{ Id: 2, Name: 'Garlic', Type: 'Vegetable' }
]
}
我可能在大写方面有些失误...我不习惯 PascalCase!