Laravel Eloquent:JSONB字段上when()方法的使用问题排查
问题分析与解决方案
你搞错了when()方法的适用场景——它是根据程序中的外部条件(比如请求参数、变量值)动态添加查询约束,而不是用来根据数据库字段的值做分支查询。你现在的需求是对数据库中不同字段值的行应用不同条件,这得用条件查询组合,不是when()。
错误原因
你用when()时,第一个参数如果是查询表达式,它会被当作布尔值判断(比如非空就为true),但这并不是你要的“判断数据库中info->type是否为Chemical”——when()的第一个参数是在查询构建阶段求值的,不是针对数据库每行的判断。所以你的第一个回调要么一直触发,要么一直不触发,完全不符合预期。
正确写法
要实现“info->type为Chemical时检查bottles是否为0,否则检查info->quantity<=0”,可以用where()结合闭包,或者直接用whereRaw写原生SQL条件:
方法1:用查询构建器的条件组合
$query->where(function ($q) { $q->where('info->type', 'Chemical') ->has('bottles', 0); })->orWhere(function ($q) { $q->where('info->type', '!=', 'Chemical') ->where('info->quantity', '<=', 0); });
方法2:用原生JSONB条件(更高效)
$query->whereRaw(" (info->>'type' = 'Chemical' AND NOT EXISTS (SELECT 1 FROM bottles WHERE bottles.parent_id = table.id)) OR (info->>'type' != 'Chemical' AND (info->>'quantity')::int <= 0) ");
(注:这里假设has('bottles',0)对应的是关联表bottles中没有关联记录,可根据你的实际关联逻辑调整原生SQL)
补充:什么时候用when()?
比如你要根据请求中是否传入type参数来添加约束,这时候用when()才是正确场景:
$type = request('type'); $query->when($type === 'Chemical', function ($q) { $q->has('bottles', 0); }, function ($q) { $q->where('info->quantity', '<=', 0); });
这时候when()的第一个参数是程序中的变量值,根据它来决定添加哪个查询约束。
内容的提问来源于stack exchange,提问作者Riza Khan
相关产品推荐
相关产品推荐

