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!