【问题标题】:Knex SQL Join Multiple Other Tables into Array on First TableKnex SQL 将多个其他表连接到第一个表上的数组中
【发布时间】:2019-10-29 06:22:14
【问题描述】:

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

Meals

Id

Vegetables

Id

Meal(参考 Meals 表)

Fruits

Id

Meal(参考 Meals 表)

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

【问题讨论】:

    标签: javascript sql knex.js


    【解决方案1】:

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

    整体架构可能不适合您(我假设)您想要实现的目标。您似乎想要类似的输出?

    {
      Id: 1, 
      Name: 'Spinach Pie',
      Ingredients: [
        { Id: 1, Name: 'Spinach', Type: 'Vegetable' },
        { Id: 2, Name: 'Garlic', Type: 'Vegetable' }
      ]
    }
    

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

    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 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, {}))
    

    这将产生:

    {
      name: 'Spinach Pie',
      ingredients: [
        { Id: 1, Name: 'Spinach', Type: 'Vegetable' },
        { Id: 2, Name: 'Garlic', Type: 'Vegetable' }
      ]
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-17
      • 1970-01-01
      • 1970-01-01
      • 2021-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-06
      相关资源
      最近更新 更多