Laravel中如何向JSON类型字段追加数据而非覆盖原有内容
实现方案
方案1:通用兼容方案(适配所有支持JSON字段的数据库)
核心逻辑是先将API响应按id分组,减少数据库交互次数,再查询已有值合并后统一更新:
// 按响应id分组,同id的所有响应归入同一组 $groupedResponses = collect($responses)->groupBy('id'); foreach ($groupedResponses as $resId => $items) { // 查询当前id已存储的JSON值,不存在则初始化空数组 $existingValues = DB::table('table')->where('res_id', $resId)->value('myvalues'); $existingValues = $existingValues ? json_decode($existingValues, true) : []; // 遍历同id的所有响应,追加新值 foreach ($items as $item) { $newValue = json_decode($item->value, true); // 若新值本身是数组则合并,单条对象则直接追加 if (is_array($newValue) && array_is_list($newValue)) { $existingValues = array_merge($existingValues, $newValue); } else { $existingValues[] = $newValue; } } // 合并完成后更新到数据库 DB::table('table')->where('res_id', $resId)->update([ 'myvalues' => json_encode($existingValues) ]); }
方案2:高性能原子操作方案(适配MySQL 5.7+/PostgreSQL等支持JSON原生操作的数据库)
使用数据库自带的JSON操作函数实现原子追加,无需提前查询,可避免并发场景下的竞态覆盖问题:
追加单个对象场景
foreach ($responses as $response) { $newValue = json_decode($response->value, true); DB::table('table') ->where('res_id', $response->id) ->update([ 'myvalues' => DB::raw('JSON_ARRAY_APPEND(IFNULL(myvalues, JSON_ARRAY()), "$", ?)'), ], [$newValue]); }
合并多个值(新值本身为数组)场景
foreach ($responses as $response) { $newValue = $response->value; // 此处直接使用JSON格式的字符串即可 DB::table('table') ->where('res_id', $response->id) ->update([ 'myvalues' => DB::raw('JSON_MERGE_PRESERVE(IFNULL(myvalues, JSON_ARRAY()), ?)'), ], [$newValue]); }
注意事项
- 建议将表中
myvalues字段的默认值设为空JSON数组[],可省去空值判断逻辑 - 同id响应量大时优先选择先分组再批量处理的逻辑,可大幅降低数据库IO压力
- 存在并发更新同id记录的场景下必须使用原生JSON函数方案,避免先查后写导致的数据覆盖
内容的提问来源于stack exchange,提问作者ira
相关产品推荐
相关产品推荐

