You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent:从三个关联表过滤并获取指定数据

需求与问题描述

我的应用中有三个数据表:products、categories和subcategories,关联关系如下:

  • product 与 category 为一对多(hasMany)关系
  • category 与 subcategory 为一对多(hasMany)关系(subcategories表包含生产日期字段)

我需要获取所有产品的名称,以及对应的分类名称、子分类名称和日期,且数据需按子分类的dateProd字段过滤,条件为('dateProd', '>=', date('Y-m-d'))。


现有模型及数据表定义

Product 模型及数据表

模型关联代码

public function categorie()
{
    return $this->hasMany('Categorie::class');
}

数据表字段

$table->string('name');

Categorie 模型及数据表

模型关联代码

public function product(): BelongsTo
{
    return $this->belongsTo(Product::class);
}

public function subcategory(): HasMany
{
    return $this->hasMany(Subcategorie::class);
}

数据表字段

$table->string('name');
$table->foreignId('porduct_id')->constrained(); // 注意:此处存在拼写错误,应为product_id

Subcategorie 模型及数据表

模型关联代码

public function category(): BelongsTo
{
    return $this->belongsTo(Category::class);
}

数据表字段

$table->string('name');
$table->date('dateProd');
$table->foreignId('category_id')->constrained();

现有视图代码

@foreach($products as $product)
    {{ $product->name }}
    @foreach($products->category as $category) <!-- 错误:应为$product->categorie,对应模型关联方法名 -->
        {{ $category->name }}
        @foreach($category->subcategory as $subcategory)
            {{ $subcategory->name }}
            {{ $subcategory->dateProd }}
        @endforeach
   @endforeach
@endforeach

解决方案

1. 修正拼写与命名规范

  • 先修复Categorie数据表中的外键拼写错误,将porduct_id改为product_id:
// Categorie 迁移文件中
$table->foreignId('product_id')->constrained();
  • 统一关联方法命名(符合Laravel复数惯例):
    • Product模型关联改为:
    public function categories()
    {
        return $this->hasMany(Categorie::class);
    }
    
    • Categorie模型关联改为:
    public function subcategories(): HasMany
    {
        return $this->hasMany(Subcategorie::class);
    }
    

2. 编写过滤查询逻辑

在控制器中使用嵌套预加载+约束查询,获取符合日期条件的数据,同时避免N+1查询问题:

use Carbon\Carbon;
use App\Models\Product;

$today = Carbon::today()->toDateString();

$products = Product::with([
    'categories' => function ($query) use ($today) {
        // 预加载分类时,过滤关联的子分类
        $query->with([
            'subcategories' => function ($subQuery) use ($today) {
                $subQuery->where('dateProd', '>=', $today);
            }
        ]);
        // 只保留存在符合条件子分类的分类
        $query->has('subcategories', '>', 0, 'and', function ($q) use ($today) {
            $q->where('dateProd', '>=', $today);
        });
    }
])
// 只保留存在符合条件分类的产品
->has('categories.subcategories', '>', 0, 'and', function ($q) use ($today) {
    $q->where('dateProd', '>=', $today);
})
->get();

如果不需要严格过滤无有效关联的产品,可去掉外层has条件。

3. 修正视图循环逻辑

根据修改后的关联方法名调整视图,同时跳过无有效子分类的分类:

@foreach($products as $product)
    <p>产品:{{ $product->name }}</p>
    @foreach($product->categories as $category)
        @if($category->subcategories->isNotEmpty())
            <p>分类:{{ $category->name }}</p>
            @foreach($category->subcategories as $subcategory)
                <p>子分类:{{ $subcategory->name }} | 生产日期:{{ $subcategory->dateProd }}</p>
            @endforeach
        @endif
    @endforeach
@endforeach

内容的提问来源于stack exchange,提问作者Albert Ndizeye

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 06:45:01