在元数据库 SQL 查询中提取 JSON 内容

Extract JSON content in Metabase SQL query

使用:Django==2.2.24Python=3.6、PostgreSQL 是底层数据库
使用 Django ORM,我可以轻松地进行各种查询,但我开始使用 Metabase,我的 SQL 可能有点生疏。

问题:
我正在尝试获取列表中项目的计数,在字典中的一个键下,存储为 JSONField:

from django.db import models
from jsonfield import JSONField

class MyTable(models.Model):
  data_field = JSONField(blank=True, default=dict)

存储在data_field中的字典示例:

{..., "my_list": [{}, {}, ...], ...}

"my_list"键下,存储的值是一个列表,其中包含一些其他字典。
在 Metabase 中,我试图计算列表中字典的数量,但更基本的东西,none 其中有效。

我试过的一些东西:
尝试:

SELECT COUNT(elem->'my_list') as my_list_count
FROM my_table, json_object_keys(data_field:json) AS elem

错误:

ERROR: syntax error at or near ":" Position: 226

尝试:

SELECT ARRAY_LENGTH(elem->'my_list') as my_list_count
FROM my_table, JSON_OBJECT_KEYS(data_field:json) AS elem

错误:

ERROR: syntax error at or near ":" Position: 233

尝试:

SELECT JSON_ARRAY_LENGTH(data_field->'my_list'::json)
FROM my_table

错误:

ERROR: invalid input syntax for type json Detail: Token "my_list" is invalid. Position: 162 Where: JSON data, line 1: my_list

尝试:

SELECT ARRAY_LENGTH(JSON_QUERY_ARRAY(data_field, '$.my_list'))
FROM my_table

错误:

ERROR: function json_query_array(text, unknown) does not exist Hint: No function matches the given name and argument types. You might need to add explicit type casts. Position: 140

基本上,我认为问题是我在尝试使用的方法中使用了错误的签名(大部分时间)。

我使用这个查询来确保我至少可以从字典中获取键:

SELECT JSON_OBJECT_KEYS(data_field::json)
FROM my_table

我无法在不添加 ::json 强制转换的情况下使用 JSON_OBJECT_KEYS(),我遇到了这个错误:

ERROR: function json_object_keys(text) does not exist Hint: No function matches the given name and argument types. You might need to add explicit type casts. Position: 127

但是通过 json 转换,我得到了预期的所有键。


感谢您的观看!


编辑:
我也发现了这个 interesting article with different solution 但 none 的解决方案有效。
还看到 没有帮助。

好的,在进一步挖掘之后,我找到了 this 篇文章,其中有正确的 format/syntax。

这段代码是我用来从 JSON 对象中成功获取列表的代码:

select data_field::json->'my_list' as the_list
from my_table 

然后,我用json_array_length()得到元素个数:

select json_array_length(data_field::json->'my_list') as number_of_elements
from my_table 

大功告成! :)

编辑:
我刚刚找到了整个恶作剧的原因。 在代码中(几年前)我们使用了这个包:

jsonfield==1.0.3

并这样使用:

from jsonfield import JSONField

问题是在后台,Postgres 将数据保存为字符串,因此需要将其转换为 JSON。 后来 Django 引入了它自己的 JSONField,它可以像你期望的那样存储数据,而不需要强制转换:

from django.contrib.postgres.fields import JSONField