在ActiveRecord中搜索jsonb列

问题描述 投票:0回答:2

我的用户模型有 jsonb 列,其名称为

raw
。看起来像这样:

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

现在我想通过

raw["client"]["tokens"]
中的令牌查找用户。我怎样才能做到这一点?

sql ruby-on-rails ruby postgresql
2个回答
2
投票

我通常首先在 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了解更多详细信息

更新2:

另一种查询方式是:

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

它应该能够在原始列上使用简单的

GIN
索引(它比上面描述的表达式索引使用更多的空间)。

CREATE INDEX index_user_raw ON users USING GIN (raw)

再次:详细信息请参阅上面的 JSON INDEXING 链接。并使用查询可视化工具来查看差异。我喜欢http://tatiyants.com/pev


0
投票

测试您的左侧值是否包含右侧值。 “包含”适用于对象和数组,因此以下查询将有效:

User.where("((raw #>> '{}')::json->>'client')::json->>'tokens' @> ?", ["asdasd"].to_json)
© www.soinside.com 2019 - 2024. All rights reserved.