【问题标题】:Laravel: Excluding filtering on many to many relationLaravel:排除对多对多关系的过滤
【发布时间】:2018-04-19 04:48:53
【问题描述】:

我有两个模型:食品和设备。 这两个模型是多对多关系的(也处理了我的 Laravel Eloquent)。所以 Food 有一些准备它所需的设备。

我想要过滤食物,其中包含输入时提供的所有设备,并且该食物不需要任何其他设备。所以换句话说 - 当输入设备包含在与某些食物相关的设备中时。


创意展示示例

例如,我有一个名为“Xyz cake”的样品食品。要准备这些食物,您需要

  • 搅拌机
  • 烤箱

假设我们输入了以下设备:

  • 搅拌机
  • 厨房机器人
  • 烤箱

在这种情况下,过滤脚本应该将我们的食物纳入结果,因为与食物相关的设备正在适合输入设备。


另一个例子:“Abc 蛋糕”。所需设备:

  • 搅拌机
  • 厨房机器人
  • 烤箱

输入设备:

  • 搅拌机
  • 厨房机器人

在这种情况下,脚本不应将食物纳入结果,因为准备食物还需要烤箱,但输入设备中不存在烤箱。


我当前的代码

$equipments 变量是包含输入设备 ID 的数组。

$query = Food::query();
$query->join('equipments_foods', function ($join) use ($equipments) {
    $join->on('foods.id', '=', 'equipments_foods.food_id');
    $join->whereIn('equipments_foods.equipment_id', $equipments);
});
$results = $query->get();

此代码无法正常工作,因为它提供的 Foods 包含来自输​​入设备的至少一个设备。

数据库是 MySQL。

请帮助我实现正常工作的过滤。

非常感谢!

【问题讨论】:

  • 通过with() 和范围查询使用预先加载。 $users = User::with('podcasts')->get(); 之类的东西,如果您有多个关系,则使用 stackoverflow.com/questions/46732845/… 之类的作用域

标签: php mysql sql laravel eloquent


【解决方案1】:

我认为以下内容可以解决您的问题。这是一个用于测试的 SQL Fiddle。 http://sqlfiddle.com/#!9/d04555/3

基本上,它完全解决了问题,使用非选定设备查找并排除所有食物。

SELECT f.*
FROM food f
WHERE NOT EXISTS (
    SELECT *
    FROM equipment e 
    INNER JOIN equipments_foods ef ON (e.id = ef.equipment_id)
    WHERE e.id NOT IN (1, 2, 3)
    AND f.id = ef.food_id
)

然后您可以创建一个模型查询范围来包含此逻辑。以下是使用 Laravel 的查询构建器编写此代码的未经测试的尝试。

$foods = Food::usingEquipment($equipment)->get();

public function scopeUsingEquipment(Builder $query, array $equipment)
{
    return $query->whereNotExists(function ($query) use ($equipment) {
        $query->select(DB::raw(1))
            ->from('equipment')
            ->join('equipments_foods', 'equipment.id', '=', 'equipments_foods.equipment_id')
            ->whereIn('equipment.id', $equipment)
            ->whereRaw('food.id = equipments_foods.food_id');
    });
}

【讨论】:

    【解决方案2】:

    我会建议你使用 laravel 的多对多数据透视表。 您的 Food 模型应如下所示

    命名空间应用程序;

    使用 Illuminate\Database\Eloquent\Model;

    类食品扩展模型 { 受保护的 $fillable = ['name'];

    公共功能设备(){

    return $this>belongsToMany('App\equipment','food_equipment','food_id','equipment_id');

    }

    公共函数 scopeRel($query){

    return $query->with('设备'); }

    }

    food_equipment 是数据透视表,而 food_id 和 equipment_id 是数据透视表中的字段。 这种关系确保了制作不同种类食物所需的所有设备都得到了适当的匹配。

    scopeRel 是一个本地范围,它将以数组的形式返回准备食物所需的所有设备。

    您可以查询模型。 Food::where('equipment_id', 1)->rel()->first();

    【讨论】:

    • 好的,谢谢。但是为什么 belongsToMany() 关系方法中有“user_id”参数呢?还有我怎样才能处理更多所需的设备?
    • @zyx4sdk user_id 是错误的,我已将其编辑为 food_id。 Food 模型中定义的关系负责处理这一点。
    【解决方案3】:

    在研究找到合适的解决方案后,我终于设法使用 Laravel Query Builder 让它工作。

    没想到这么简单。

    $query = Food::query();
    $query->where(function ($query) use ($inputEquipment) {
        $query->doesntHave('equipments');
        $query->orWhere(function ($query) use ($inputEquipment) {
            foreach ($inputEquipment as $equipmentId) {
                $query->whereHas('equipments', function ($query) use ($equipmentId) {
                    $query->where('id', $equipmentId);
                });
            }
        });
    });
    $results = $query->get();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      • 2013-09-14
      • 2021-08-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多