4

If I have two json arrays of strings in mysql, is there a native(or not native) way to merge these two arrays into one with unique strings? If I try json_merge I get the following result with duplicates:

set @array1 =JSON_EXTRACT('["apple","pear","banana"]', '$');
set @array2 =JSON_EXTRACT('["pear","banana","apple","kiwi"]', '$');
select json_merge(@array1,@array2);
    > ["apple", "pear", "banana", "pear", "banana", "apple", "kiwi"]

And If is try json_merge_preserve gives me the same result:

set @array1 =JSON_EXTRACT('["apple","pear","banana"]', '$');
set @array2 =JSON_EXTRACT('["pear","banana","apple","kiwi"]', '$');
select json_merge_preserve(@array1,@array2);
    > ["apple", "pear", "banana", "pear", "banana", "apple", "kiwi"]

Is there a function that will return the unique array?

["apple",  "banana", "pear", "kiwi"]

Edit: json_merge_patch doesn't work because it only replaces the first array with the second:

set @array1 =JSON_EXTRACT('["apple","grape","banana"]', '$');
set @array2 =JSON_EXTRACT('["pear","banana","apple","kiwi"]', '$');
select json_merge_patch(@array1,@array2);
 > ["pear", "banana", "apple", "kiwi"]

In this case I lose "grape". I believe that the logic in patch is 0 : 'val', 1:'val2' merge with 0:val3 then 0 : 'val3', 1:'val2'

4 Answers 4

5

If the question still lives, here's a simple solution using MySQL 8.0's JSON_TABLE.

set @a1 ='["apple","grape","banana","banana","pear"]';
set @a2 ='["pear","banana","apple","kiwi","banana","apple"]';

select fruit
from json_table(
  json_merge_preserve(@a1, @a2),
  '$[*]' columns (
    fruit varchar(255) path '$'
  )
) as fruits
group by fruit; # get distinct values

# gives
apple
grape
banana
pear
kiwi

To get a one-line response, we have to drop group by and get a bit more creative.

Unfortunately, JSON_ARRAYAGG doesn't support distinct directive, so we'll have to use GROUP_CONCAT:

select group_concat(distinct fruit)
from json_table(
  json_merge_preserve(@a1, @a2),
  '$[*]' columns (
    fruit varchar(255) path '$'
  )
) as fruits;
# without group by directive!

# gives: apple,banana,grape,kiwi,peas

To get a proper json array on-line response, we just play around with CONCATs:

select cast(
  concat('["', group_concat(distinct fruit separator '", "'), '"]')
  as json)
...

# gives: ["apple", "banana", "grape", "kiwi", "pear"]

EDIT:

I've found out a proper JSON_ARRAYAGG solution using one more nested virtual table to group results in.

select json_arrayagg(fruit)
from (
  select fruit
  from json_table(
    json_merge_preserve(@a1, @a2),
    '$[*]' columns (
      fruit varchar(255) path '$'
    )
  ) as fruits
  group by fruit -- group here!
) as unique_fruits;

Read my Best Practices for using MySQL as JSON storage :)

Sign up to request clarification or add additional context in comments.

Comments

1

After too much thinking, and thanks to @lefred. I found a hack that can accomplish this. This is way too hacky, but i will publish it while someone else comes with a better implementation or the mysql guys make a proper function for this.

First, we replace the string strategically to create a json object instead of an array. Then, we use json_merge_path and finally we use json_keys to obtain an array :V

set @array1 ='["apple","grape","banana","banana","pear"]';
set @array2 ='["pear","banana","apple","kiwi","banana","apple"]';

set @aux1 = REPLACE(REPLACE(REPLACE(@array1, ',', ' : "1", '), ']', ' : "1" }'), '[', '{');
set @aux2 = REPLACE(REPLACE(REPLACE(@array2, ',', ' : "1", '), ']', ' : "1" }'), '[', '{');
select @aux1, @aux2;
select json_keys(json_merge_patch(json_extract(@aux1, '$'),json_extract(@aux2,'$')))

> ["kiwi", "pear", "apple", "grape", "banana"]

1 Comment

This works, but it's rather ugly. Please, see my answer based on JSON_TABLE.
1

Use SELECT DISTINCT:

set @array1 =JSON_EXTRACT('["apple","grape","banana"]', '$');
set @array2 =JSON_EXTRACT('["pear","banana","apple","kiwi"]', '$');

select json_arrayagg(fruit) from (
    select 
        distinct fruit 
    from json_table(
        json_merge_preserve(@array1, @array2), 
        '$[*]' columns (fruit varchar(255) path '$')
    ) fruits
) f;

1 Comment

Yeah, the distinct would work as well. you are missing the json_arrayagg to return the json array, like this: select json_arrayagg(fruit) from (select distinct fruit from json_table( json_merge_preserve(@array1, @array2), '$[*]' columns (fruit varchar(255) path '$') ) fruits) f;
0

According to the documentation, json_merge_preserve preserves duplicates. Also, if you are using MySQL 8.0.3 or over, json_merge is deprecated and json_merge_preserve should be used. I think that you need to use JSON_MERGE_PATCH.

More details here https://database.guide/json_merge_preserve-merge-multiple-json-documents-in-mysql/

5 Comments

No, that only replaces the first array with the second
Yeah, I see that now... did you have a look at this stackoverflow.com/questions/39508478/… ? The question does not have an answer, but the question itself might help you.
So, are you suggesting is a bad idea to store json string arrays in MySQL?
Is there a specific need for storing data that way? It is usually hard to deal with data that has been stored this way. And in my experience, data stored like that is not intended to be used in operations or filters.
XDevApi now supports collections. The fact MySQL supports that, ask for tools to manage json in more robust way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.