
在 Laravel 中直接通过 column->path 语法更新 JSON 字段的嵌套对象时,若传入已编码的 JSON 字符串会导致双重转义;正确做法是逐字段指定路径更新,或使用原生 SQL/JSON 函数实现原子性批量更新。
在 laravel 中直接通过 `column->path` 语法更新 json 字段的嵌套对象时,若传入已编码的 json 字符串会导致双重转义;正确做法是逐字段指定路径更新,或使用原生 sql/json 函数实现原子性批量更新。
在 Laravel 中操作数据库 JSON 字段(如 MySQL 的 JSON 类型或 PostgreSQL 的 jsonb)时,常遇到一个典型陷阱:试图用 json_encode() 后的字符串直接赋值给 column->key 路径,结果导致 JSON 值被意外转义为字符串。例如:
// ❌ 错误:导致 {"data": "{\"total\":22,\"time\":5}"}
$json_data = json_encode(['total' => 22, 'time' => 5]);
DB::table('items')->where('id', 1)->update(['meta->data' => $json_data]);
这是因为 Laravel 的 -> 路径语法底层仍依赖 SQL 的 JSON 路径表达式(如 MySQL 的 JSON_SET 或 JSON_REPLACE),而直接赋值字符串会被当作纯文本写入,而非解析为 JSON 对象。
✅ 推荐解决方案如下:
方案一:逐字段更新(兼容性最佳,适用于所有 Laravel 版本 + MySQL/PostgreSQL)
显式拆解目标数组,为每个嵌套键指定完整 JSON 路径:
$data = ['total' => 22, 'time' => 5];
DB::table('items')
->where('id', 1)
->update([
'meta->data->total' => $data['total'],
'meta->data->time' => $data['time'],
]);
✅ 优势:无需额外依赖,语义清晰,避免序列化干扰;
⚠️ 注意:仅更新指定字段,其余 data 下的属性(如 data->user_id)保持不变。
方案二:使用原生 JSON 函数(MySQL 5.7+ / PostgreSQL,原子性强)
利用数据库原生能力一次性合并/替换整个子对象,避免多次查询与竞态:
// ✅ MySQL 示例:使用 JSON_SET 替换整个 "data" 对象
DB::statement(
"UPDATE items SET meta = JSON_SET(meta, '$.data', ?) WHERE id = ?",
[json_encode(['total' => 22, 'time' => 5]), 1]
);
// ✅ PostgreSQL 示例(jsonb):使用 jsonb_set
DB::statement(
"UPDATE items SET meta = jsonb_set(meta, '{data}', ?::jsonb) WHERE id = ?",
[json_encode(['total' => 22, 'time' => 5]), 1]
);
? 提示:Laravel 10+ 在 Illuminate/Database/Query/Builder 中已内置对 JSON_SET 等函数的部分支持,但跨平台一致性仍建议封装为 DB::raw() 或使用包(如 staudenmeir/laravel-json-relations)。
方案三:读-改-写(通用但需事务保护)
若结构复杂或需条件逻辑,可先取回、修改再写入,务必包裹事务防止并发覆盖:
DB::transaction(function () use ($data) {
$item = DB::table('items')->where('id', 1)->first();
$current = json_decode($item->meta, true) ?: [];
// 深度合并或覆盖 data 子对象
$current['data'] = array_merge($current['data'] ?? [], $data);
DB::table('items')->where('id', 1)->update([
'meta' => json_encode($current, JSON_UNESCAPED_UNICODE)
]);
});
总结与最佳实践
- ❌ 避免对 column->path 直接赋值 json_encode() 字符串;
- ✅ 优先使用逐字段路径更新(方案一),简洁安全;
- ✅ 高并发或需原子性时,选用原生 JSON 函数(方案二),性能更优;
- ⚠️ 使用读-改-写(方案三)时,必须加事务,并考虑乐观锁或版本字段;
- ? 所有 JSON 操作前建议校验字段类型(如 JSON_VALID(meta))及路径存在性,提升健壮性。
通过合理选择更新策略,即可精准、高效、安全地维护 JSON 字段中的嵌套结构。











