Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL group and merge JSON values

Tags:

json

mysql

I am using some native JSON fields to store information about some application entities in a MySQL 5.7.10 database. I can have 'N' rows per "entity" and need to roll-up and merge the JSON objects together, and any conflicting keys should replace instead of merge. I can do this through code, but if I can do it natively and efficiently in MySQL even better.

I have attempted this using a combination of GROUP_CONCAT and JSON_MERGE, but I've run into two issues:

  1. JSON_MERGE won't take the results of GROUP_CONCAT as a valid argument
  2. JSON_MERGE combines conflicting keys instead of replacing them. What I really need is more of a JSON_SET but with 'N' number of JSON docs instead of "key, value" notation.

Is this possible with the current MySQL JSON implementation?

like image 353
ryanmovista Avatar asked Jan 26 '16 16:01

ryanmovista


People also ask

What is JSON aggregate?

JSON_AGG combines values and returns the combined data as a single JSON row. NULL values are included in the aggregation.

Can MySQL parse JSON?

In MySQL, JSON values are written as strings. MySQL parses any string used in a context that requires a JSON value, and produces an error if it is not valid as JSON.

What is Json_arrayagg in MySQL?

JSON_ARRAYAGG returns a JSON array containing an element for each value in a given set of JSON or SQL values. It acts on a column or an expression that evaluates to a single value. Returns NULL in the case of an error, or if the result contains no rows. JSON_ARRAYAGG cannot currently be used as a window function.

What is Json_objectagg?

JSON_OBJECTAGG( key , value ) Takes two column names or expressions as arguments, the first of these being used as a key and the second as a value, and returns a JSON object containing key-value pairs. Returns NULL if the result contains no rows, or in the event of an error.


2 Answers

You could do something like the following:

SELECT
    CAST(CONCAT(
        '[',
        GROUP_CONCAT(
            DISTINCT JSON_OBJECT(
                'foo', mytable.foo,
                'bar', mytable.bar
            )
        ),
        ']'
    ) AS JSON) AS myJsonArr
FROM mytable
GROUP BY mytable.someGroup;
like image 171
DataVader Avatar answered Sep 21 '22 20:09

DataVader


  1. JSON_MERGE won't take the results of GROUP_CONCAT as a valid argument

GROUP_CONCAT gives a,b,c,d, not a JSON array. Use JSON_ARRAYAGG (introduced in MySQL 5.7.22), which works just like group_concat, but gives a correct array ["a", "b", "c", "d"], that should be accepted with JSON functions.

Prior to 5.7.22, you need to use a workaround:

cast(
  concat('["',                                    // begin bracket and quote
         group_concat(`field` separator '", "'),  // separator comma and quotes
         '"]'                                     // end quote and bracket
 ) as json
)
  1. JSON_MERGE combines conflicting keys instead of replacing them. What I really need is more of a JSON_SET but with 'N' number of JSON docs instead of "key, value" notation.

Use JSON_MERGE_PATCH instead, as introduced in MySQL 5.7.22. JSON_MERGE is a synonym for JSON_MERGE_PRESERVE.

See https://dev.mysql.com/doc/refman/5.7/en/json-function-reference.html.


Read my Best Practices for using MySQL as JSON storage.

like image 39
ΔO 'delta zero' Avatar answered Sep 20 '22 20:09

ΔO 'delta zero'