2017-08-13 80 views
3

我有一个JSON字段来保存帖子的标签。列出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"] 

我只想列出所有标签与他们的流行程度(甚至没有他们)是这样的:

TAG_2:3,

TAG_1:2,

tag_3:1

回答

1

这里的设置:

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"]}'; 

如果你知道代码会在任何标记阵列的最大数量,你可以使用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" | 
+----+---------+ 

你需要尽可能多的被联合子查询的最长阵列中的标签数量。

然后,你可以把它放进派生表,并对其执行聚合:

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 | 
+---------+-------+ 

这将是更容易,如果你存储在第二表,而不是在一个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 | 
+-------+-------+ 

无论您拥有多少个标签,此解决方案都能正常工作。您不需要知道每个ID的标签列表的最大长度。

当您需要存储半结构化数据的“文档”时,但只有当您将文档视为不可简化的数据值时,JSON才是很好的选择。只要您需要访问文档的元素并对其应用关系操作,面向文档的方法就显示出其弱点。

+0

谢谢!很有帮助。在这工作一个星期! – user43857

相关问题