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

Eloquent多条件关联查询问题:筛选特定状态的预约与收据

问题分析

你遇到的问题本质是:whereHas 仅用于筛选存在符合条件关联数据的主模型(Reservation),但不会影响 with 方法加载关联数据的范围——所以即使预约存在未付款收据,with('bill.receipts') 仍然会加载该预约下的所有收据(包括已付款的)。

解决方案

要实现「筛选状态为Checked-In的预约,且仅加载其关联的UNPAID状态收据」,需要在用whereHas筛选主模型的同时,给with的关联加载添加条件约束,确保只返回符合要求的收据。

正确写法示例

$reservations = Reservation::with([
        'rooms',
        'bill.receipts' => function ($query) {
            // 给receipts关联添加过滤条件,只加载UNPAID状态的
            $query->where('status', 'UNPAID');
        },
        'bill.receipts.foodOrders.food'
    ])
    ->where('status', 'Checked-In')
    ->whereHas('bill.receipts', function ($query) {
        // 确保预约存在至少一个UNPAID状态的收据
        $query->where('status', 'UNPAID');
    })
    ->get();

写法说明

  • whereHas('bill.receipts', ...):负责过滤出存在未付款收据且状态为Checked-In的预约,这一步保证不会返回完全没有未付款收据的预约。
  • with('bill.receipts' => function ($query) {...}):在加载receipts关联时,额外添加status = 'UNPAID'的条件,确保最终返回的每个预约下只包含未付款的收据。
  • 关联嵌套(bill.receipts.foodOrders.food)会自动继承receipts的过滤条件,只加载未付款收据对应的食品订单和食品信息。

另一种等效写法(拆分whereHas层级)

如果你习惯拆分关联层级,也可以写成:

$reservations = Reservation::with([
        'rooms',
        'bill.receipts' => fn($query) => $query->where('status', 'UNPAID'),
        'bill.receipts.foodOrders.food'
    ])
    ->where('status', 'Checked-In')
    ->whereHas('bill', function ($query) {
        $query->whereHas('receipts', fn($subquery) => $subquery->where('status', 'UNPAID'));
    })
    ->get();
为什么从Receipt查询能正常工作

因为从Receipt出发时,你直接对Receipt模型添加了where('status', 'UNPAID')条件,同时通过with加载关联的预约,自然只会返回未付款的收据及其关联数据——这和从Reservation出发的逻辑方向相反,但核心都是对需要返回的关联数据添加直接过滤。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 03:07:41