Laravel多外键Pivot表按多条件筛选关联影院实现方法
三表多对多关联下按双条件筛选影院数据实现方案
现有结构说明
当前共3张业务主表+1张三向关联中间表:
- cities(城市表),表结构:

- movies(电影表),表结构:

- theatres(影院表),表结构:

- 中间表
city_movie_theatre用于关联三张主表,表结构:
需求为查询同时匹配指定city_id和movie_id的影院记录,当前代码未加入城市维度筛选,无法返回正确结果。
当前已有代码
控制器代码:
class MovieController extends Controller { public function test(){ $city_id=1; $movie_id=1; $th=Movie::where('id',$movie_id)->first(); dd($th->theatre); } }
Movie模型:
class Movie extends Model { use HasFactory; public function theatre(){ return $this->belongsToMany(Theatre::class,'city_movie_theatre'); } public function city(){ return $this->belongsToMany(City::class,'city_movie_theatre'); } }
Theatre模型:
class Theatre extends Model { use HasFactory; public function city(){ return $this->belongsToMany(City::class,'city_movie_theatre'); } public function movie(){ return $this->belongsToMany(Movie::class,'city_movie_theatre','theatre_id','movie_id'); } }
中间表模型:
use Illuminate\Database\Eloquent\Relations\Pivot; class City_Movie_Theatre extends Pivot { use HasFactory; protected $table='city_movie_theatre'; }
实现方案
核心问题说明
原有代码不生效的核心原因:
- 直接通过动态属性
$th->theatre取关联数据时,ORM会先执行全量关联查询,无法再追加中间表筛选条件 - 多对多关联未声明中间表额外字段,无法直接对
city_id做条件过滤
最快可用修改
不需要调整模型,直接修改控制器代码,通过关联查询构造器的wherePivot方法筛选中间表字段即可:
class MovieController extends Controller { public function test(){ $city_id = 1; $movie_id = 1; // 先拿到电影模型实例,再通过关联构造器加中间表条件,最后查结果集 $theatres = Movie::find($movie_id) ->theatre() // 调用关联方法拿到查询构造器,不是直接取属性 ->wherePivot('city_id', $city_id) // 筛选中间表的city_id ->get(); dd($theatres); } }
推荐的模型规范优化
建议把关联方法改为复数形式(一个电影对应多个影院/城市,语义更清晰),同时显式声明关联外键和中间表字段,避免ORM自动推断出错:
// Movie 模型 class Movie extends Model { use HasFactory; public function theatres(){ return $this->belongsToMany( Theatre::class, 'city_movie_theatre', 'movie_id', 'theatre_id' )->withPivot('city_id'); // 声明中间表携带的额外字段 } public function cities(){ return $this->belongsToMany( City::class, 'city_movie_theatre', 'movie_id', 'city_id' )->withPivot('theatre_id'); } }
// Theatre 模型 class Theatre extends Model { use HasFactory; public function cities(){ return $this->belongsToMany( City::class, 'city_movie_theatre', 'theatre_id', 'city_id' )->withPivot('movie_id'); } public function movies(){ return $this->belongsToMany( Movie::class, 'city_movie_theatre', 'theatre_id', 'movie_id' )->withPivot('city_id'); } }
优化后查询写法和上面一致,后续需要获取中间表字段时可以直接通过$model->pivot->字段名取值。
可选查询方式
如果需要从影院入口筛选,也可以用whereHas做关联存在性查询,最终生成的SQL和上面写法等价:
$theatres = Theatre::whereHas('movies', function($query) use ($movie_id, $city_id){ $query->where('movies.id', $movie_id) ->where('city_movie_theatre.city_id', $city_id); })->get();
内容的提问来源于stack exchange,提问作者pyrogrammer
相关产品推荐
相关产品推荐

