Laravel 6中嵌套JSON数组的存储与特定节点数据检索问题
解决Laravel中嵌套JSON字段的数据查询与提取问题
看起来你在处理多层嵌套的JSON数据时遇到了瓶颈,别着急,我们一步步拆解问题来解决它。
首先,先理清你的数据结构:add_ons是一个嵌套了多层数组的JSON字段,要定位到whiteOne的价格,需要分两步走:正确筛选出目标记录,再从记录中提取深层嵌套的值。
一、修复你的查询语句
你之前用的Item::whereJsonContains('add_ons->data->name','sauces')->get()无法正确匹配,核心原因是data是一个数组,你需要明确告诉MySQL去检查数组内的所有元素,而不是直接访问data->name。正确的写法应该是:
// 筛选出add_ons.data数组中存在name为"sauces"的记录 $items = Item::whereJsonContains('add_ons->data[*]->name', 'sauces')->get();
如果要更精准地筛选出包含whiteOne的记录,可以用多层数组的路径匹配:
// 筛选出所有包含whiteOne的Item记录 $items = Item::whereJsonContains('add_ons->data[*]->type[*]->type[*]->name', 'whiteOne')->get();
如果你的MySQL版本对[*]语法支持有限,也可以用whereRaw结合原生JSON函数实现:
$items = Item::whereRaw('JSON_CONTAINS(add_ons->"$.data[*].type[*].type[*].name", \'"whiteOne"\')')->get();
二、提取目标价格值
当你拿到目标记录(比如用find(16)获取特定Item)后,Laravel会自动将JSON字段转换为数组,你可以逐层访问嵌套结构:
$item = Item::find(16); // 逐层访问:先拿到data数组的第一个sauces项 $sauceGroup = $item->add_ons['data'][0]; // 拿到type数组中的"white sauce"项 $whiteSauce = $sauceGroup['type'][0]; // 从white sauce的子type数组中找到whiteOne的价格 $whiteOnePrice = collect($whiteSauce['type'])->firstWhere('name', 'whiteOne')['price']; // 输出结果:10 echo $whiteOnePrice;
如果担心数组索引的不确定性(比如data里可能有多个元素),可以用集合方法做更安全的查找:
$item = Item::find(16); // 先找到data中name为sauces的项 $sauceGroup = collect($item->add_ons['data'])->firstWhere('name', 'sauces'); if ($sauceGroup) { // 找到type中name为white sauce的项 $whiteSauce = collect($sauceGroup['type'])->firstWhere('name', 'white sauce'); if ($whiteSauce) { // 提取whiteOne的价格 $whiteOnePrice = collect($whiteSauce['type'])->firstWhere('name', 'whiteOne')['price']; echo $whiteOnePrice; } }
这种方式更健壮,即使JSON结构中数组元素顺序变化,也能正确定位目标值。
三、优化小技巧
如果你需要频繁访问这类深层嵌套的值,可以在Item模型中定义访问器,简化后续代码:
// 在app/Models/Item.php中添加访问器 public function getWhiteOnePriceAttribute() { $sauceGroup = collect($this->add_ons['data'])->firstWhere('name', 'sauces'); if (!$sauceGroup) return null; $whiteSauce = collect($sauceGroup['type'])->firstWhere('name', 'white sauce'); if (!$whiteSauce) return null; $whiteOne = collect($whiteSauce['type'])->firstWhere('name', 'whiteOne'); return $whiteOne ? $whiteOne['price'] : null; }
之后你就可以直接用$item->white_one_price快速获取价格,非常便捷!
内容的提问来源于stack exchange,提问作者Debu
相关产品推荐
相关产品推荐

