查询Rails中的Postgres JSON数组字段
我试图在Postgres数据库中查询某个值。 我在users
表中有一个名为groups
的字段,可以用以下任一方式表示:
1。
groups: {"data"=>[{"serie"=>5, "year"=>3, "specialization"=>"Matematica", "management_id"=>1, "group_number"=>2}, {"serie"=>5, "year"=>3, "specialization"=>"Matematica", "management_id"=>1, "group_number"=>2}]}
2。
groups: [{"serie"=>5, "year"=>3, "specialization"=>"Matematica", "management_id"=>1, "group_number"=>2}, {"serie"=>5, "year"=>3, "specialization"=>"Matematica", "management_id"=>1, "group_number"=>2}]
我对这两种陈述都很好。 但是,我似乎无法找到如何让所有使用serie 5的用户说出来。 我尝试了多个查询:
@users = User.where("groups ->> 'data' @> ?", {serie: 5}) @users = User.where("groups -> 'data' @> '?'", {serie: 5}) @users = User.where("groups ->> 'data' ->> 'serie' = ?", 5)
还有许多其他尝试,有些比其他尝试更愚蠢(见上文)。 我该怎么办?
我已经能够确定:
select groups -> 'data' ->> 'serie' from users; ERROR: cannot extract field from a non-object.
但是以下查询有效:
select json_array_elements(groups -> 'data') ->> 'serie' from users;
我认为我没有在列中正确传递数据。 我提供的哈希是:
pry(#)> @response['data']['user'] => {"last_name"=>"Doe1", "first_name"=>"John1", "email"=>"c0f45@example.com", "groups"=> {"data"=> [{"serie"=>5, "year"=>3, "specialization"=>"Matematica", "management_id"=>1, "group_number"=>2}, {"serie"=>5, "year"=>3, "specialization"=>"Matematica", "management_id"=>1, "group_number"=>2}]}}
在保存资源之前,如下所示:
pry(#)> @resource => #[{"serie"=>5, "year"=>3, "specialization"=>"Matematica", "management_id"=>1, "group_number"=>2}, {"serie"=>5, "year"=>3, "specialization"=>"Matematica", "management_id"=>1, "group_number"=>2}]}>
假设:
- Postgres 9.4或更高版本 。
- “让所有在系列5中的用户”应该是:
“至少有一个包含{"serie": 5}
数组元素{"serie": 5}
。可能还有其他数组元素。” - 使用您的第一个更短的数据格式。 没有冗余的“数据”键。
简短回答:使用jsonb
代替json
,这只是起作用:
User.where("groups @> ?", '[{"serie": 5}]')
注意方括号使右侧操作数成为JSON 数组 。
为什么?
这里突出的误解: 数据类型json
与jsonb
。
你没有声明实际的表定义,但是你后来评论了json
并且问题中有一个提示:
select json_array_elements(groups -> 'data') ->> 'serie' from users;
json_array_elements()
仅适用于json
,必须是jsonb_array_elements()
。
但是你试着使用jsonb
运算符 @>
,这对于json
是不可能的 :
groups -> 'data' @> '?'
运算符->
返回与左侧输入相同的类型。 但@>
仅为jsonb
定义,而不是为json
定义。
然后尝试使用运算符@>
作为左侧操作数的text
。 也不可能 :
groups ->> 'data' @> ?
对于各种类型(包括Postgres数组),运算符@>
有变体,但不适用于text
而不适用于json
。
所以,简短的回答:使用jsonb
而不是json
。 这也允许使用非常有效的索引 :
- 用于在JSON数组中查找元素的索引
json
对于数据类型json
您可以使用:
SELECT * FROM users u WHERE EXISTS ( SELECT 1 FROM json_array_elements(u.groups) elem WHERE elem ->> 'serie' = '5' );
演示
jsonb
:
SELECT * FROM ( VALUES (1, jsonb '[{"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2} , {"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]') , (2, '[{"serie":7, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2} , {"serie":8, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]') , (3, '[{"serie":9, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2} , {"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]') ) users(id, groups) WHERE groups @> '[{"serie": 5}]';
json
:
SELECT * FROM ( VALUES (1, json '[{"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2} , {"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]') , (2, '[{"serie":7, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2} , {"serie":8, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]') , (3, '[{"serie":9, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2} , {"serie":5, "year":3, "specialization":"Matematica", "management_id":1, "group_number":2}]') ) users(id, groups) WHERE EXISTS ( SELECT 1 FROM json_array_elements(users.groups) elem WHERE elem ->> 'serie' = '5' );