为jsonb值搜索构建Activerecord / SQL查询

时间:2017-07-09 17:24:21

标签: ruby-on-rails ruby postgresql activerecord jsonb

目前,对于使用不同参数的定期搜索,我建立了这个ActiveRecord查询:

current_user.documents.order(:updated_at).reverse_order.includes(:groups,:rules)

现在,我通常会在此where子句上执行此搜索。但是,我现在需要在jsonb字段中搜索具有某个的所有行,如key:value对。我已经能够用我的SQL做类似的事情了,这种语法(数据字段只有两层嵌套):

SELECT 
    * 
FROM 
    (SELECT 
         * 
    FROM 
        (SELECT 
            * 
        FROM 
            documents
        ) A, 
        jsonb_each(A.data)
    ) B, 
    jsonb_each_text(B.value) ASC C 
WHERE 
    C.value = '30';

但是,我想使用当前的ActiveRecord搜索来进行此查询(其中包括组/规则急切加载)。

我正在努力使用逗号,我理解这是一个隐式连接,它在显式连接之前执行,所以当我尝试这样的事情时:

select * from documents B join (select * from jsonb_each(B.data)) as A on true;
ERROR:  invalid reference to FROM-clause entry for table "b"
LINE 1: ...* from documents B join (select * from jsonb_each(B.data)) a...
                                                           ^
HINT: There is an entry for table "b", but it cannot be referenced from this part of the query.

但我不明白如何引用完整的"表"我在创建连接调用之前创建的ActiveRecord查询,以及使用隐式连接的逗号语法来工作。

另外,我是一名SQL爱好者,所以如果你看到一些改进或其他方法,请告诉我们。

编辑:文件说明表:

enter image description here

                                                        Table "public.documents"
Column      |            Type             |                       Modifiers                        | Storage  | Stats target | Description 
------------+-----------------------------+--------------------------------------------------------+----------+--------------+-------------
id          | integer                     | not null default nextval('documents_id_seq'::regclass) | plain    |              | 
document_id | character varying           |                                                        | extended |              | 
name        | character varying           |                                                        | extended |              | 
size        | integer                     |                                                        | plain    |              | 
last_updated| timestamp without time zone |                                                        | plain    |              | 
user_id     | integer                     |                                                        | plain    |              | 
created_at  | timestamp without time zone |                                                        | plain    |              | 
updated_at  | timestamp without time zone |                                                        | plain    |              | 
kind        | character varying           |                                                        | extended |              | 
uid         | character varying           |                                                        | extended |              | 
access_token_id | integer                     |                                                        | plain    |              | 
data        | jsonb                       | not null default '{}'::jsonb                           | extended |              | 

索引:     " documents_pkey" PRIMARY KEY,btree(id) ```

示例行,首先匹配搜索' 30' (数据是最后一个字段):

2104 | 24419693037                                          | LsitHandsBackwards.jpg                   |        |                         |       1 | 2017-06-25 21:45:49.121686 | 2017-07-01 21:32:37.624184 | box          | 221607127         |              15 | {"owner": {"born": "to make history", "price": 30}}
2177 | /all-drive/uml flows/typicaluseractivity.svg         | TypicalUserActivity.svg                  |  12375 | 2014-08-11 02:21:14     |       1 | 2017-07-07 14:00:11.487455 | 2017-07-07 14:00:11.487455 | dropbox      | 325694961         |              20 | {"owner": {}}

1 个答案:

答案 0 :(得分:2)

您可以使用类似于您已经展示的查询:

SELECT
    d.id, d.data
FROM
    documents AS d 
    INNER JOIN json_each(d.data)  AS x ON TRUE 
    INNER JOIN json_each(x.value) AS y ON TRUE 
WHERE
    cast(y.value as text) = '30';

假设您的数据如下:

INSERT INTO documents
    (data)
VALUES
   ('{"owner": {"born": "to make history", "price": 30}}'),
   ('{"owner": {}}'),
   ('{"owner": {"born": "to make history", "price": 50}, "seller": {"worth": 30}}')
;

你得到的结果是:

id | data                                                                        
-: | :---------------------------------------------------------------------------
 1 | {"owner": {"born": "to make history", "price": 30}}                         
 3 | {"owner": {"born": "to make history", "price": 50}, "seller": {"worth": 30}}

您可以在 dbfiddle here

检查它(以及对数据的一些分步查看)