2017-08-13 2 views
3

J'ai un champ JSON pour enregistrer les tags de publication.Liste tous les éléments de tableau d'un champ MySQL JSON

id:1, content:'...', tags: ["tag_1", "tag_2"] 

id:2, content:'...', tags: ["tag_3", "tag_2"] 

id:3, content:'...', tags: ["tag_1", "tag_2"] 

Je veux juste énumérer tous les tags avec leurs popularités (ou même sans eux) quelque chose comme ceci:

TAG_2: 3,

tag_1: 2,

TAG_3: 1

Répondre

1

est ici la configuration:

create table t (id serial primary key, content json); 
insert into t set content = '{"tags": ["tag_1", "tag_2"]}'; 
insert into t set content = '{"tags": ["tag_3", "tag_2"]}'; 
insert into t set content = '{"tags": ["tag_1", "tag_2"]}'; 

Si vous connaissez le nombre maximum de balises dans un tableau de balises, vous pouvez extraire toutes les balises en utilisant UNION:

select id, json_extract(content, '$.tags[0]') AS tag from t 
union 
select id, json_extract(content, '$.tags[1]') from t; 

+----+---------+ 
| id | tag  | 
+----+---------+ 
| 1 | "tag_1" | 
| 2 | "tag_3" | 
| 3 | "tag_1" | 
| 1 | "tag_2" | 
| 2 | "tag_2" | 
| 3 | "tag_2" | 
+----+---------+ 

Vous avez besoin d'autant que le sous-requêtes filles fusionnées nombre de balises dans le plus long tableau.

Ensuite, vous pouvez mettre ceci dans une table dérivée et d'effectuer une agrégation sur elle:

select tag, count(*) as count 
from ( 
    select id, json_extract(content, '$.tags[0]') as tag from t 
    union 
    select id, json_extract(content, '$.tags[1]') from t 
) as t2 
group by tag 
order by count desc; 

+---------+-------+ 
| tag  | count | 
+---------+-------+ 
| "tag_2" |  3 | 
| "tag_1" |  2 | 
| "tag_3" |  1 | 
+---------+-------+ 

Ce serait plus facile si vous avez enregistré des balises dans une deuxième table au lieu d'un tableau JSON:

create table tags (id bigint unsigned, tag varchar(20) not null, primary key (id, tag)); 
insert into tags set id = 1, tag = 'tag_1'; 
insert into tags set id = 1, tag = 'tag_2'; 
insert into tags set id = 2, tag = 'tag_3'; 
insert into tags set id = 2, tag = 'tag_2'; 
insert into tags set id = 3, tag = 'tag_1'; 
insert into tags set id = 3, tag = 'tag_2'; 

select tag, count(*) as count 
from tags 
group by tag 
order by count desc; 

+-------+-------+ 
| tag | count | 
+-------+-------+ 
| tag_2 |  3 | 
| tag_1 |  2 | 
| tag_3 |  1 | 
+-------+-------+ 

Cette solution fonctionne quel que soit le nombre de tags par identifiant. Vous n'avez pas besoin de connaître la longueur maximale de la liste des tags par identifiant. JSON est agréable quand vous avez besoin de stocker un 'document' de données semi-structurées, mais seulement quand vous traitez le document comme une valeur de données irréductible. Dès que vous avez besoin d'accéder à des éléments du document et de leur appliquer des opérations relationnelles, l'approche documentaire montre sa faiblesse.

+0

Merci! Très utile. Travailler sur cela pour une semaine! – user43857