Baz*_*xer 7 php mysql json mysql-json
对于最近的开发项目,我们使用MySQL 5.7,因此我们可以利用最新的JSON功能......
我正在构建一个UPDATE查询,其中应该将嵌套的json对象插入/添加到JSON类型的attributes-column中,请参阅下面的查询.
UPDATE `table` SET `table`.`name` = 'Test',
`table`.`attributes` = JSON_SET(
`table`.`attributes`,
"$.test1", "Test 1",
"$.test2.test3", "Test 3"
)
Run Code Online (Sandbox Code Playgroud)
当我执行此查询时,attributes-field包含数据
{"test1": "Test 1"}
Run Code Online (Sandbox Code Playgroud)
而不是通缉
{"test1", "Test 1", "test2": {"test3", "Test 3"}}
Run Code Online (Sandbox Code Playgroud)
还尝试使用JSON_MERGE,但是当我多次执行它时,它会创建一个类似的JSON对象
{"test1": ["Test 1", "Test 1", "Test 1"... etc.], "test2": {"test3": ["Test 3", "Test 3", "Test 3"... etc.]}}
Run Code Online (Sandbox Code Playgroud)
那么,当节点不存在时,JSON_SET不起作用?JSON_MERGE合并到无穷大?
JSON对象中使用的键可以由用户定义,因此无法为所有可能的键创建空的JSON对象.我们是否真的需要在每个UPDATE查询之前执行JSON_CONTAINS/JSON_CONTAINS_PATH查询,以确定是否需要使用JSON_SET或JSON_MERGE/JSON_APPEND?
我们正在寻找一种方法来获得始终有效的查询,所以当"$.test4.test5.test6"给出时,它将扩展当前的JSON对象,添加完整路径......如何做到这一点?
fyr*_*rye 11
假设你想要最终的结果
{"test1": "Test 1", "test2": {"test3": "Test 3"}}
Run Code Online (Sandbox Code Playgroud)
在您的示例中attributes,正在更新的列设置为{"test1": "Test 1"}
查看您的初始UPDATE查询,我们可以看到$.test2.test3不存在.所以它不能被设置为
JSON_SET()在JSON文档中插入或更新数据并返回结果.如果任何参数为NULL或路径(如果给定)未找到对象,则返回NULL.
意思是MySQL可以添加$.test2,但由于$.test2不是对象,MySQL无法添加$.test2.test3.
因此,您需要$.test2通过执行以下操作将其定义为json对象.
mysql> SELECT * FROM testing;
+----+---------------------+
| id | attributes |
+----+---------------------+
| 1 | {"test1": "Test 1"} |
+----+---------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
mysql> UPDATE testing
-> SET attributes = JSON_SET(
-> attributes,
-> "$.test1", "Test 1",
-> "$.test2", JSON_OBJECT("test3", "Test 3")
-> );
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0
Run Code Online (Sandbox Code Playgroud)
mysql> SELECT * FROM testing;
+----+---------------------------------------------------+
| id | attributes |
+----+---------------------------------------------------+
| 1 | {"test1": "Test 1", "test2": {"test3": "Test 3"}} |
+----+---------------------------------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
因此,您需要明确地告诉MySQL密钥作为JSON对象存在,而不是依赖于MySQL点表示法.
这类似于PHP也定义了不存在的对象属性值.
$a = (object) ['test1' => 'Test 1'];
$a->test2->test3 = 'Test 3';
//PHP Warning: Creating default object from empty value
Run Code Online (Sandbox Code Playgroud)
要摆脱错误,您需要先定义$a->test2为对象.
$a = (object) ['test1' => 'Test 1'];
$a->test2 = (object) ['test3' => 'Test 3'];
Run Code Online (Sandbox Code Playgroud)
或者,您可以在使用点表示法之前测试和创建对象,以设置值.虽然对于较大的数据集,这可能是不合需要的
mysql> UPDATE testing
-> SET
-> attributes = JSON_SET(attributes, "$.test2", IFNULL(attributes->'$.test2',JSON_OBJECT())),
-> attributes = JSON_SET(attributes, "$.test4", IFNULL(attributes->'$.test4', JSON_OBJECT())),
-> attributes = JSON_SET(attributes, "$.test4.test5", IFNULL(attributes->'$.test4.test5', JSON_OBJECT())),
-> attributes = JSON_SET(
-> attributes,
-> "$.test2.test3", "Test 3"
-> );
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
Run Code Online (Sandbox Code Playgroud)
mysql> SELECT * FROM testing;
+----+---------------------------------------------------------------------------+
| id | attributes |
+----+---------------------------------------------------------------------------+
| 1 | {"test1": "Test 1", "test2": {"test3": "Test 3"}, "test4": {"test5": {}}} |
+----+---------------------------------------------------------------------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
虽然在任何一种情况下如果未提供原始数据,JSON_OBJECT函数调用将清空嵌套对象的属性值.但正如您在上一个JSON_SET查询中所看到的那样,$.test1未在定义中提供attributes,并且它保持不变,因此可以从查询中省略未修改的属性.
JSON_MERGE_PATCH现在,从 MySQL 版本 5.7.22 开始,最简单的方法是像这样使用:
UPDATE `table` SET `attributes` =
JSON_MERGE_PATCH(`attributes`, '{"test2": {"test3": "Test 3"}, "test4": {"test5": {}}}')
Run Code Online (Sandbox Code Playgroud)
{"test1": "Test 1", "test2": {"test3": "Test 3"}, "test4": {"test5": {}}}这给出了您的示例中的预期结果。