我使用 PostgreSQL 9.5 和Rails 5.我想查询下面显示的jsonb
列,其中包含一组JSON对象,以返回包含{{1}的所有JSON数组元素并且还执行计数
我使用的 SQL 显示在json数据下面。运行查询只返回一个空数组。
这就是我的{"kind":"person"}
数据:
jsonb
我想要一个sql查询返回:
'[
{"kind":"person", "filter_term":"56","selected_attr":"customer"},
{"kind":"email", "filter_term":"marketer","selected_attr":"job_title"}
]'
和另一个返回数组的查询,以便我可以在我的应用程序中调用count并在其上循环以创建表单:
data
----------------------------------------------------------------------
'{"kind":"person", "filter_term":"56","selected_attr":"customer"}'
(1 row)
我尝试了这个SQL查询:
data
----------------------------------------------------------------------
'[{"kind":"person", "filter_term":"56","selected_attr":"customer"}]'
(1 row)
我也试过这个问题:
"SELECT * FROM \"segments\" WHERE (payload @> '[{\"kind\":\"person\"}]')"
这是第三个查询:
"SELECT payload FROM segments WHERE payload @> '[{\"kind\":\"person\"}]'::jsonb;"
模特:
"SELECT * FROM segments s WHERE s.payload->'\"#{a}\"' @> '[{\"kind\":\"person\"}]';"
迁移:
class Segment < ApplicationRecord
store_accessor :payload,:kind, :filter_term, :selected_model_name, :selected_attr, :limit, :selected_operator
end
答案 0 :(得分:10)
假设这个表定义:
CREATE TABLE segments (segments_id serial PRIMARY KEY, payload jsonb);
使用这样的JSON值:
INSERT INTO segments (payload)
VALUES ('[
{
"kind": "person",
"limit": "1",
"filter_term": "56",
"selected_attr": "customer",
"selected_operator": "less_than"
},
{
"kind": "email",
"filter_term": "marketer",
"selected_attr": "job_title",
"selected_operator": "equals"
}
]'
);
"kind":"person"
(不是嵌套的JSON对象{"kind":"person"}
)的JSON数组的元素 - 并计算数组元素和表行(可能有每行多个匹配的数组元素。)要获取列jsonb
中包含符合条件的segments
值的 行数 :
SELECT count(*)
FROM segments s
WHERE s.payload @> '[{"kind":"person"}]';
获取 所有符合条件的JSON数组元素 (自身为JSON对象) - 加上元素的总数(可能同时大于上面的数量:< / p>
SELECT j.*
FROM segments s
JOIN LATERAL jsonb_array_elements(s.payload) j(elem) ON j.elem @> '{"kind":"person"}'
WHERE s.payload @> '[{"kind":"person"}]';
返回:
elem ------------------------------------------------------------ {"kind": "person", "limit": "1", "filter_term": "56", ... }
要一次 :
SELECT j.*, count(*) OVER () AS ct_elem, s.ct_rows
FROM (
SELECT payload, count(*) OVER () AS ct_rows
FROM segments
WHERE payload @> '[{"kind":"person"}]'
) s
JOIN LATERAL jsonb_array_elements(s.payload) j(elem) ON j.elem @> '{"kind":"person"}';
返回(对于包含更多条目的表):
elem | ct_elem | ct_rows --------------------------+---------+--------- {"kind": "person", ... } | 4 | 3 {"kind": "person", ... } | 4 | 3 ...
但是 我认为你真的想要这个 :
SELECT a.*
, sum(ct_elem_row) OVER () AS ct_elem_total
, count(*) OVER () AS ct_rows
FROM segments s
JOIN LATERAL (
SELECT json_agg(j.elem) AS filtered_payload, count(*) AS ct_elem_row
FROM jsonb_array_elements(s.payload) j(elem)
WHERE j.elem @> '{"kind":"person"}'
) a ON ct_elem_row > 0
WHERE s.payload @> '[{"kind":"person"}]';
返回(对于包含更多条目的表):
filtered_payload | ct_elem_row | ct_elem_total | ct_rows -----------------------------------------------------+-------------+---------------+--------- [{"kind": "person", ... }] | 1 | 4 | 3 [{"kind": "person", ... }] | 1 | 4 | 3 [{"kind": "person", ... }, {"kind": "person", ... }] | 2 | 4 | 3
这标识匹配的行,然后选择匹配的数组元素,并且每行只构建一个数组。加上重要。
为了获得最佳性能,您将获得jsonb_path_ops
GIN索引,如:
CREATE INDEX segments_path_ops_gin_idx ON segments
USING gin (payload jsonb_path_ops);
(但是,提供更多不同查询的更通用的索引可能是更好的选择。)
相关:
<强>术语强>
我们正在处理一个包含 JSON数组的JSON对象,保存为Postgres jsonb
数据类型 - 简称为“JSON数组”,但不是一个“JSON数组”。