Knex SQL 将多个其他表连接到第一个表上的数组中

Arc*_*Arc 1 javascript sql knex.js

目前我正在使用 Knex 查询 MSSQL 数据库。我有一张这样的表:

Meals

Id

Vegetables

Id

Meal (参考膳食表)

Fruits

Id

Meal (参考膳食表)

因此,一餐 ID 可以包含多种蔬菜或水果。我希望得到一个包含所有蔬菜数组和结果中所有水果数组的膳食 ID 的结果。现在使用knex('meals').innerJoin('fruits', 'meals.id', 'fruits.meal'),我得到了多个对象。

Ric*_*her 5

是的,您肯定会通过该查询获得多个对象。您没有指定什么 to SELECT,因此数据库返回所有内容。

对于(我假设)您要实现的目标,整体架构可能不正确。似乎您想要类似这样的输出?

{
  Id: 1, 
  Name: 'Spinach Pie',
  Ingredients: [
    { Id: 1, Name: 'Spinach', Type: 'Vegetable' },
    { Id: 2, Name: 'Garlic', Type: 'Vegetable' }
  ]
}
Run Code Online (Sandbox Code Playgroud)

在您当前的模式下,每种蔬菜或水果只能搭配一顿饭。这是一种 HAS ONE 关系:“一种蔬菜吃一顿饭”。显然,我们可以在各种不同的菜肴中使用任何给定的蔬菜,因此我们需要以不同的方式思考问题。正确的思考方式是,一种蔬菜有很多餐,一顿有很多蔬菜。这将我们引向一个带有连接表的结构:

Meals
 - Id
 - Name

Ingredients
 - Id
 - Name
 - Type

MealsIngredients
 - Id
 - Meal
 - Ingredient
Run Code Online (Sandbox Code Playgroud)

(我不一定会这样写一本真正的食谱书,但出于演示目的......)

这会给我们一个这样的查询:

knex('Meals')
  .select('Meals.Name as mealName', 'Ingredients.*')
  .innerJoin('MealsIngredients', 'Meals.Id', 'MealsIngredients.Meal')
  .innerJoin('Ingredients', 'Ingredients.Id', 'MealsIngredients.Ingredient')
  .where('Meals.Id', mealId)
Run Code Online (Sandbox Code Playgroud)

它不会让你到达你想要的地方,但到目前为止:

[
  { mealName: 'Spinach Pie', Id: 1, Name: 'Spinach', Type: 'Vegetable' },
  { mealName: 'Spinach Pie', Id: 2, Name: 'Garlic', Type: 'Vegetable' }
]
Run Code Online (Sandbox Code Playgroud)

要将其与餐点的详细信息结合起来,有多种选择。我们可以发出两个单独的查询,或某种数组聚合(我不太熟悉 SQL Server 在那里的选项)。鉴于这里的要求相对简单,您可能只需在 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, {}))
Run Code Online (Sandbox Code Playgroud)

这将产生:

{
  name: 'Spinach Pie',
  ingredients: [
    { Id: 1, Name: 'Spinach', Type: 'Vegetable' },
    { Id: 2, Name: 'Garlic', Type: 'Vegetable' }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我可能在大小写方面有些失误……我不习惯 PascalCase!