[英]Query on Postgres JSON array field in Rails
我正在尝试查询 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}]
我对这两种表示都很好。 但是,我似乎无法找到如何获得意甲 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;
我认为我没有正确传递列中的数据。 我要创建的 hash 是:
pry(#<Overrides::RegistrationsController>)> @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(#<Overrides::RegistrationsController>)> @resource
=> #<User id: nil, provider: "email", uid: "", first_name: "John1", last_name: "Doe1", email: "c0f45@example.com", role: "Student", created_at: nil, updated_at: nil, 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}]}>
假设:
{"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
必须是jsonb_array_elements()
。 但是您尝试使用未为json
定义的jsonb
运算符@>
:
groups -> 'data' @> '?'
运算符->
返回与左侧输入相同的类型。 但是@>
只为jsonb
定义,而不是为json
定义。
然后您尝试将运算符@>
用于text
作为左侧操作数。 也不可能:
groups ->> 'data' @> ?
运算符@>
有多种类型(包括 Postgres 数组)的变体,但不适用于text
和json
。
所以,简短的回答:使用jsonb
而不是json
。 这也允许使用非常有效的索引:
json
对于数据类型json
您可以使用:
SELECT *
FROM users u
WHERE EXISTS (
SELECT 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 FROM json_array_elements(users.groups) elem
WHERE elem ->> 'serie' = '5'
);
在 Rails 中过滤 JSON
Event.create( payload: [{ "name": 'Jack', "age": 12 },
{ "name": 'John', "age": 13 },
{ "name": 'Dohn', "age": 24 }]
Event.where('payload @> ?', '[{"age": 12}]')
#You can also filter by name key
Event.where('payload @> ?', '[{"name": "John"}]')
#You can also filter by {"name":"Jack", "age":12}
Event.where('payload @> ?', {"name":"Jack", "age":12}.to_json)
您可以在此处找到更多相关信息
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.