查询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 数组

为什么?

这里突出的误解: 数据类型jsonjsonb

你没有声明实际的表定义,但是你后来评论了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' );