16

最近の開発プロジェクトでは、MySQL 5.7 を使用しているため、最新の JSON 関数を利用できます...

私は UPDATE クエリを作成しています。ここでは、ネストされた json オブジェクトを JSON 型の属性列に挿入/追加する必要があります。以下のクエリを参照してください。

UPDATE `table` SET `table`.`name` = 'Test',
    `table`.`attributes` = JSON_SET(
         `table`.`attributes`,
         "$.test1", "Test 1",
         "$.test2.test3", "Test 3"
     )

このクエリを実行すると、属性フィールドにデータが含まれます

{"test1": "Test 1"} 

欲しいものの代わりに

{"test1", "Test 1", "test2": {"test3", "Test 3"}}

JSON_MERGE も使用しようとしましたが、複数回実行すると、次のような JSON オブジェクトが作成されます

{"test1": ["Test 1", "Test 1", "Test 1"... etc.], "test2": {"test3": ["Test 3", "Test 3", "Test 3"... etc.]}}

では、ノードが存在しない場合、JSON_SET は機能しないのでしょうか? JSON_MERGE は無限にマージしますか?

JSON オブジェクトで使用されるキーはユーザーが定義できるため、可能なすべてのキーに対して空の JSON オブジェクトを作成することはできません。JSON_SET または JSON_MERGE / JSON_APPEND を使用する必要があるかどうかを判断するために、各 UPDATE クエリの前に JSON_CONTAINS / JSON_CONTAINS_PATH クエリを実行する必要がありますか?

常に機能するクエリを作成する方法を探しているので、"$.test4.test5.test6"が指定されると、現在の JSON オブジェクトが拡張され、フル パスが追加されます...どうすればこれを行うことができますか?

4

4 に答える 4

20

MySQL バージョン 5.7.13 の時点で、

{"test1": "Test 1", "test2": {"test3": "Test 3"}}

あなたの例attributesでは、更新されている列はに設定されています{"test1": "Test 1"}

最初のUPDATEクエリを見ると、$.test2.test3存在しないことがわかります。したがって、次のように設定することはできません

JSON_SET() JSON ドキュメントのデータを挿入または更新し、結果を返します。いずれかの引数が NULL の場合、または path が指定されている場合、オブジェクトが見つからない場合は 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)
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
mysql> SELECT * FROM testing;
+----+---------------------------------------------------+
| id | attributes                                        |
+----+---------------------------------------------------+
|  1 | {"test1": "Test 1", "test2": {"test3": "Test 3"}} |
+----+---------------------------------------------------+
1 row in set (0.00 sec)

そのため、MySQL のドット表記に頼る代わりに、キーが JSON オブジェクトとして存在することを MySQL に明示的に伝える必要があります。

これは、PHP が存在しないオブジェクトのプロパティ値を定義する方法と似ています。

$a = (object) ['test1' => 'Test 1'];
$a->test2->test3 = 'Test 3';

//PHP Warning:  Creating default object from empty value

エラーを取り除くには、まず$a->test2オブジェクトとして定義する必要があります。

$a = (object) ['test1' => 'Test 1'];
$a->test2 = (object) ['test3' => 'Test 3'];

または、ドット表記を使用して値を設定する前に、オブジェクトをテストして作成することもできます。大規模なデータセットでは、これは望ましくない場合があります。

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
mysql> SELECT * FROM testing;
+----+---------------------------------------------------------------------------+
| id | attributes                                                                |
+----+---------------------------------------------------------------------------+
|  1 | {"test1": "Test 1", "test2": {"test3": "Test 3"}, "test4": {"test5": {}}} |
+----+---------------------------------------------------------------------------+
1 row in set (0.00 sec)

どちらの場合でも、元のデータが提供されていない場合、JSON_OBJECT 関数呼び出しは、ネストされたオブジェクトのプロパティ値を空にします。JSON_SETしかし、最後のクエリからわかるよう$.test1に、 は の定義で提供されておらずattributes、そのまま残っていたため、変更されていないプロパティはクエリから省略できます。

于 2016-07-12T13:28:47.547 に答える
3

Fyrye、アンサーをありがとう、どうもありがとう!データの構造は固定されておらず、レコードごとに異なる可能性があるため、単一のクエリで JSON オブジェクト全体を自動的に生成するクエリを生成できるソリューションが必要でした。

JSON_SET(attributes, "$.test2", IFNULL(attributes->'$.test2',JSON_OBJECT()))メソッドを使用したソリューションが本当に気に入っています。JSON_MERGE検索を続けたので、関数を使用して自分で解決策も見つけました。

更新を実行しているときJSON_MERGE、サブノードを持つすべてのキーについて、空の JSON オブジェクトをデータベースのフィールドにマージするために使用しているので、データベースの JSON フィールドで使用でき、その後、JSON_SET値を更新します。したがって、完全なクエリは次のようになります。

UPDATE table SET
    -> attributes = JSON_MERGE(
    -> attributes, '{"test2": {}, "test4": {"test5": {}}}'),
    -> attributes = JSON_SET(attributes, "$.test2.test3", "Test 3");

このクエリを実行すると、結果は次のようになります。

 mysql> SELECT * FROM testing;
 +----+---------------------------------------------------------------------------+
 | id | attributes                                                                |
 +----+---------------------------------------------------------------------------+
 |  1 | {"test1": "Test 1", "test2": {"test3": "Test 3"}, "test4": {"test5": {}}} |
 +----+---------------------------------------------------------------------------+
 1 row in set (0.00 sec)

現時点ではどちらの方法が優れているかはわかりませんが、今のところ両方とも機能します。1 回の更新で 10.000 行がどのように実行されるかを確認するために、将来的にいくつかの速度テストを行う予定です。

于 2016-07-14T08:34:40.083 に答える