在ActiveRecord中搜索jsonb列

时间:2017-07-11 07:16:46

标签: sql ruby-on-rails ruby postgresql

我的用户模型有jsonb列,其名称为raw。它看起来像这样:

{"client"=>{"tokens"=>["asdasd"]}}

现在我想通过raw["client"]["tokens"]中的令牌找到用户。我怎么能这样做?

1 个答案:

答案 0 :(得分:1)

我通常首先在SQL控制台中制作此类查询,然后将其转换为ActiveRecord。

您可以在Postgres中导航哈希键。查询

SELECT
  raw #> '{client,tokens}'
FROM users

将仅返回该路径中的tokens数组。现在我们需要检查它是否包含我们正在寻找的值。查询

SELECT
  raw #> '{client,tokens}' ? 'asdasd'
FROM users

将为具有匹配令牌的行选择t。现在,您可以将其移至WHERE部分:

SELECT
*
FROM users
WHERE  raw #> '{client,tokens}' ? 'asdasd'

如果这选择了您的期望,那么您可以将其转换为AR:

User.where("config #> '{client, tokens}' ? :token", token: 'asdasd')

请注意,我无法使用?进行参数替换,而是使用:token。另请注意,这仅适用于JSONB(Postgres 9.4 + https://www.postgresql.org/docs/9.4/static/functions-json.html#FUNCTIONS-JSONB-OP-TABLE

更新

你应该(tm)(我没有测试过这个)相处:

CREATE INDEX index_tokens ON users USING GIN ((raw #> '{client, tokens}'));

有关详细信息,请参阅https://www.postgresql.org/docs/9.6/static/datatype-json.html#JSON-INDEXING

UPDATE2:

另一种查询方式是:

raw @> '{"client": {"tokens": ["asdasd"]}}'   

哪个应该能够在原始列上使用简单的GIN索引(使用比上述表达式索引更多的空间)。

CREATE INDEX index_user_raw ON users USING GIN (raw)

再次:详细信息请参阅上面的JSON INDEXING链接。并使用Query Visualizer查看差异。我喜欢http://tatiyants.com/pev