这可能是远景,但是有什么方法可以通过查询限制JSONB数据?
我们正在调查MongoDB与PostgreSQL JSONB之间的差异,这可能是一个关键因素。
答案 0 :(得分:1)
我同时使用了MongoDB和PostgreSQL(使用JSONB)和IMO,PostgreSQL赢得了90%的时间。
这是因为现实生活中的大多数数据本质上都是关系型的,而PostgreSQL提供了两全其美的优势。它是一个功能强大的关系数据库,但在需要时也具有JSONB的灵活性(例如JSON对于非结构化数据而言可能是完美的)。
它的劣势是巨大的(咳嗽)-MongoDB可以赢得胜利,例如当有大量无限制关系的原始JSON数据(或可以轻松转换为JSON的数据)时。
可以通过以下示例很好地说明PostgreSQL JSONB的功能:-
让我们按如下方式创建表(t
):-
create table t (
id serial primary key,
data jsonb);
...带有一些演示数据...
insert into t (id, data)
values (1, '[{"name": "A", "age": 20},
{"name": "B", "age": 21},
{"name": "C", "age": 22},
{"name": "D", "age": 23},
{"name": "E", "age": 24},
{"name": "F", "age": 25},
{"name": "G", "age": 26}]'),
(2, '[{"name": "H", "age": 27},
{"name": "I", "age": 28},
{"name": "J", "age": 29},
{"name": "K", "age": 30},
{"name": "L", "age": 31}]'),
(3, '[{"name": "M", "age": 32},
{"name": "N", "age": 33},
{"name": "O", "age": 34},
{"name": "P", "age": 35},
{"name": "Q", "age": 36}]');
如果我们仅从t
中选择全部,我们将在data
列中获得3行并带有JSONB数组。
select *
from t;
----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | data
----+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | [{"age": 20, "name": "A"}, {"age": 21, "name": "B"}, {"age": 22, "name": "C"}, {"age": 23, "name": "D"}, {"age": 24, "name": "E"}, {"age": 25, "name": "F"}, {"age": 26, "name": "G"}]
2 | [{"age": 27, "name": "H"}, {"age": 28, "name": "I"}, {"age": 29, "name": "J"}, {"age": 30, "name": "K"}, {"age": 31, "name": "L"}]
3 | [{"age": 32, "name": "M"}, {"age": 33, "name": "N"}, {"age": 34, "name": "O"}, {"age": 35, "name": "P"}, {"age": 36, "name": "Q"}]
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
然后我们可以使用data
函数在jsonb_array_elements
列中“取消嵌套” JSONB数组-这将返回17行id
和data
JSONB对象。
select id,
jsonb_array_elements(data)
from t;
----+--------------------------
id | data
----+--------------------------
1 | {"age": 20, "name": "A"}
1 | {"age": 21, "name": "B"}
1 | {"age": 22, "name": "C"}
1 | {"age": 23, "name": "D"}
1 | {"age": 24, "name": "E"}
1 | {"age": 25, "name": "F"}
1 | {"age": 26, "name": "G"}
2 | {"age": 27, "name": "H"}
2 | {"age": 28, "name": "I"}
2 | {"age": 29, "name": "J"}
2 | {"age": 30, "name": "K"}
2 | {"age": 31, "name": "L"}
3 | {"age": 32, "name": "M"}
3 | {"age": 33, "name": "N"}
3 | {"age": 34, "name": "O"}
3 | {"age": 35, "name": "P"}
3 | {"age": 36, "name": "Q"}
-------------------------------
然后我们可以对上面的上一个“未嵌套”查询进行分页:-
select id,
jsonb_array_elements(data)
from t
limit 5; -- return 1st 5
----+---------------------------
id | data
----+---------------------------
1 | {"age": 20, "name": "A"}
1 | {"age": 21, "name": "B"}
1 | {"age": 22, "name": "C"}
1 | {"age": 23, "name": "D"}
1 | {"age": 24, "name": "E"}
--------------------------------
select id,
jsonb_array_elements(data)
from t
limit 5 offset 5; -- return next 5
----+---------------------------
id | data
----+---------------------------
1 | {"age": 25, "name": "F"}
1 | {"age": 26, "name": "G"}
2 | {"age": 27, "name": "H"}
2 | {"age": 28, "name": "I"}
2 | {"age": 29, "name": "J"}
--------------------------------
我们可以进一步迈出这一步,并且可以再次按id
进行分组,并使用jsonb_agg
函数将JSON放回数组中:-
with t_unnested as (
select id,
jsonb_array_elements(data) as data
from t
limit 5 offset 5
)
select id, jsonb_agg (data)
from t_unnested
group by id;
----+--------------------------------------------------------------------------------
id | data
----+--------------------------------------------------------------------------------
1 | [{"age": 25, "name": "F"}, {"age": 26, "name": "G"}]
2 | [{"age": 27, "name": "H"}, {"age": 28, "name": "I"}, {"age": 29, "name": "J"}]
----+--------------------------------------------------------------------------------
我们可以接受之前的查询,并使用新字段重新构建新对象,例如person_id
和person_info
。这个
将返回带有新的自定义JSONB对象的单列(每id
再次一行)。
with t_unnested as (
select id,
jsonb_array_elements(data) as data
from t
limit 5 offset 5
),
t_person as (
select jsonb_build_object (
'person_id', id,
'person_info', jsonb_agg (data)
) as person
from t_unnested
group by id
)
select person from t_person;
-----------------------------------------------------------------------------------------------------------------
person
-----------------------------------------------------------------------------------------------------------------
{"person_id": 1, "person_info": [{"age": 25, "name": "F"}, {"age": 26, "name": "G"}]}
{"person_id": 2, "person_info": [{"age": 27, "name": "H"}, {"age": 28, "name": "I"}, {"age": 29, "name": "J"}]}
-----------------------------------------------------------------------------------------------------------------
上一个查询返回了2行,我们可以再次使用jsonb_agg
函数,即创建单行。
with t_unnested as (
select id,
jsonb_array_elements(data) as data
from t
limit 5 offset 5
),
t_person as (
select jsonb_build_object (
'person_id', id,
'person_info', jsonb_agg (data)
) as person
from t_unnested
group by id
)
select jsonb_agg(person) from t_person;
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
person
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[{"person_id": 1, "person_info": [{"age": 25, "name": "F"}, {"age": 26, "name": "G"}]}, {"person_id": 2, "person_info": [{"age": 27, "name": "H"}, {"age": 28, "name": "I"}, {"age": 29, "name": "J"}]}]
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
希望这显示了JSONB / PostgreSQL在存储JSONB,取消分页(和重新分页)JSON数组中的功能。