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

Laravel HasMany关联模型筛选:获取含全部指定物品类型的公园

解决Laravel中筛选包含全部指定类型物品的公园问题

嗨,我来帮你优化这个筛选逻辑~首先咱们先分析下你原来的代码为什么没效果:

你一开始用的where('type', json_decode($request->type_list)),其实Laravel会把数组参数转成whereIn条件,但whereHas的逻辑是只要关联模型中有一个符合条件就会返回该Park,所以这样写只能筛选出包含任意一种指定类型的公园,而不是你需要的全部包含。

你后来用循环取交集的方法虽然可行,但确实不够优雅,而且会执行多次数据库查询,数据量大的时候性能会打折扣。下面给你两个更高效简洁的方案:

方案一:链式调用多个whereHas

这是最直观的方式,遍历你的类型数组,给每个类型添加一个whereHas条件,这样每个条件都必须满足,也就是公园必须同时拥有所有指定类型的物品:

$typesArray = json_decode($request->type_list, true);

// 初始化查询构造器
$parksQuery = Park::query();

// 给每个类型添加whereHas条件
foreach ($typesArray as $type) {
    $parksQuery->whereHas('items', function ($query) use ($type) {
        $query->where('type', $type);
    });
}

// 执行查询
$parks = $parksQuery->get();

这个方法的优势是逻辑清晰,一次数据库查询就能完成,性能比循环取交集好很多。

方案二:用groupBy + having统计匹配类型数量

如果你的类型数组可能有重复(或者想更灵活地统计),可以用分组统计的方式,确保公园关联的物品类型覆盖了所有指定类型:

$typesArray = json_decode($request->type_list, true);
$requiredTypeCount = count($typesArray);

$parks = Park::whereHas('items', function ($query) use ($typesArray) {
    // 先筛选出包含任意指定类型的物品
    $query->whereIn('type', $typesArray);
})
->groupBy('parks.id') // 按公园分组
// 统计该公园关联的不重复指定类型数量,必须等于需要的类型总数
->havingRaw('COUNT(DISTINCT items.type) = ?', [$requiredTypeCount])
->get();

这里用DISTINCT是为了避免同一个类型有多个物品时重复计数(比如一个公园有3个喷泉,只算1种类型)。

对比你的原方案

你原来的循环取交集方法,会执行N次数据库查询(N是类型数量),当类型多或者公园数据量大时,数据库压力会比较大。上面两个方案都是一次查询,代码更简洁,性能也更优。

另外别忘了处理边界情况:如果传入的type_list是空数组,你可以根据业务需求返回所有公园,或者直接返回空集合哦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:18:36