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

Symfony 6 Doctrine Repository查询问题:按主分类各取5篇文章

解决Symfony 6中每个主分类下获取5篇产品的问题

方法一:利用窗口函数(适用于MySQL 8+/PostgreSQL等支持窗口函数的数据库)

这种方法效率更高,一次查询就能完成需求。假设你的实体关系如下:

  • MainCategory(主分类):包含多个SubCategory
  • SubCategory(子分类):属于一个MainCategory,包含多个Product
  • Product(产品):属于一个SubCategory

在你的ProductRepository中添加如下方法:

use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;

public function findLastFivePerMainCategory()
{
    $qb = $this->createQueryBuilder('p')
        ->select('p, sc, mc')
        ->join('p.subCategory', 'sc')
        ->join('sc.mainCategory', 'mc')
        ->addSelect('ROW_NUMBER() OVER (PARTITION BY mc.id ORDER BY p.createdAt DESC) AS rn')
        ->having('rn <= 5')
        ->orderBy('mc.id', 'ASC')
        ->addOrderBy('p.createdAt', 'DESC');

    $query = $qb->getQuery();
    // 处理返回结果,整理成按主分类分组的结构
    $results = $query->getResult();
    
    $groupedResults = [];
    foreach ($results as $item) {
        $mainCategory = $item[0]->getSubCategory()->getMainCategory();
        $groupId = $mainCategory->getId();
        if (!isset($groupedResults[$groupId])) {
            $groupedResults[$groupId] = [
                'mainCategory' => $mainCategory,
                'products' => []
            ];
        }
        $groupedResults[$groupId]['products'][] = $item[0];
    }
    
    return array_values($groupedResults);
}

说明:

  • ROW_NUMBER() OVER (PARTITION BY mc.id ORDER BY p.createdAt DESC) 按主分类ID分组,每组内按产品创建时间倒序给产品编号
  • having('rn <= 5') 筛选出每组的前5条数据
  • 最后通过循环把结果整理成按主分类分组的结构,方便业务层直接使用

方法二:遍历主分类分别查询(兼容所有数据库)

如果你的数据库不支持窗口函数,可以先获取所有主分类,再逐个查询对应主分类下的最新5篇产品:

首先在ProductRepository中添加单分类查询方法:

use App\Entity\MainCategory;

public function findLastFiveByMainCategory(MainCategory $mainCategory)
{
    return $this->createQueryBuilder('p')
        ->join('p.subCategory', 'sc')
        ->where('sc.mainCategory = :mainCategory')
        ->setParameter('mainCategory', $mainCategory)
        ->orderBy('p.createdAt', 'DESC')
        ->setMaxResults(5)
        ->getQuery()
        ->getResult();
}

然后在业务层(如Controller或Service)中调用:

// 注入MainCategoryRepository和ProductRepository
$mainCategories = $this->mainCategoryRepository->findAll();
$results = [];

foreach ($mainCategories as $mc) {
    $results[] = [
        'mainCategory' => $mc,
        'products' => $this->productRepository->findLastFiveByMainCategory($mc)
    ];
}

说明:

  • 这种方法兼容性强,无需数据库支持窗口函数
  • 若主分类数量较多,会执行多次查询,性能略低于窗口函数方案

注意事项

  • 确保实体间的关联映射配置正确,比如SubCategory中存在指向MainCategory的关联字段,且ORM注解配置无误
  • 可根据实际需求调整orderBy的排序字段(如updatedAt或自定义排序字段)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 23:45:37