PHP中使用JSON_SET更新嵌套JSON对象的指定键值
解决JSON_SET更新嵌套数组对象时丢失其他属性的问题
问题根源
你之所以会丢失对象的其他属性,是因为错误地用新对象直接替换了整个数组元素(比如把$.b[0]作为路径,赋值{"fin": "新值"}),而不是精准定位到对象内的fin键进行单独更新。
正确解决方案
场景1:按数组索引更新指定对象的fin键
如果知道要更新的对象在b数组中的索引(比如第一个元素,索引为0),直接指定fin键的完整路径即可:
$newFinValue = "新的fin值"; $index = 0; // 要更新的对象在b数组中的索引 $sql = "UPDATE 你的表名 SET json字段名 = JSON_SET(json字段名, :path, :newFinValue)"; $stmt = $pdo->prepare($sql); $stmt->bindValue(':path', "$.b[$index].fin", PDO::PARAM_STR); $stmt->bindParam(':newFinValue', $newFinValue, PDO::PARAM_STR); $stmt->execute();
场景2:按对象属性匹配更新(比如按id找目标对象)
如果不知道索引,需要根据对象的某个属性(比如id)匹配目标对象,结合JSON_SEARCH定位路径:
$targetId = 1; // 要匹配的对象id $newFinValue = "新的fin值"; $sql = "UPDATE 你的表名 SET json字段名 = JSON_SET( json字段名, -- 截取JSON_SEARCH返回的id路径,替换为fin路径 JSON_UNQUOTE(JSON_SEARCH(json字段名, 'one', :targetId, NULL, '$.b[*].id')) ->> '$[0:-3]' || '.fin', :newFinValue ) -- 确保存在匹配的对象 WHERE JSON_CONTAINS(json字段名, JSON_OBJECT('id', :targetId), '$.b')"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':targetId', $targetId, PDO::PARAM_INT); $stmt->bindParam(':newFinValue', $newFinValue, PDO::PARAM_STR); $stmt->execute();
代码解释:
JSON_SEARCH(json字段名, 'one', :targetId, NULL, '$.b[*].id'):查找b数组中所有id等于targetId的路径,返回格式类似"$.b[0].id"->> '$[0:-3]':截取路径字符串,去掉最后的.id,得到$.b[0]- 拼接
.fin后,最终路径为$.b[0].fin,JSON_SET只会更新这个键,不会影响对象的其他属性
关键注意点
- 永远不要直接替换整个数组元素(比如
$.b[0]),必须精准到要更新的键的完整路径 - 确保JSON路径的语法正确,MySQL的JSON路径用
$表示根节点,数组索引用[n],对象键用.键名
内容的提问来源于stack exchange,提问作者Gelxxxx
相关产品推荐
相关产品推荐

