使用jsonb数组的Rails(postgres)查询

Obv*_*ity 4 postgresql activerecord ruby-on-rails jsonb

我的产品模型有一个jsonb字段specs(我们使用ActiveRecord管理它store_accessor).我的许多产品的规格都有一个称为哈希的规范spec_options.

在此之前,这个spec_option领域只是文字.现在它需要是一个数组.

之前用于查询此字段的产品的范围是:

scope :with_spec_options, ->(spec_options) { 
    where("'#{spec_options}'::jsonb \? (specs->>'spec_option')") 
}
Run Code Online (Sandbox Code Playgroud)

Ruby等价物(只是为了帮助理解这是做什么):

select{ |product| spec_options.include?(product.specs['spec_option']) }
Run Code Online (Sandbox Code Playgroud)

ActiveRecord等价物(如果spec_option是常规列):

where(spec_option: spec_options)
Run Code Online (Sandbox Code Playgroud)

但是,现在这specs['spec_options']是一个数组,我不能这样做.我想我需要使用postgres的?|jsonb运算符,但我无法弄清楚如何将此操作的右侧转换为正确的格式.

Ruby等价物:

def self.with_spec_options(spec_options)
    all.select{|product| 
        if product.specs['spec_options'].present?
            product.specs['spec_options'].any?{|option|
                spec_options.include?(option)
            }
        else
            false
        end
    }
end
Run Code Online (Sandbox Code Playgroud)

有人有想法吗?

Rob*_*bel 11

你想要使用的是@>运算符,它测试你的左手值是否包含右手值."包含"适用于对象和数组,因此以下查询将起作用:

SELECT * FROM products WHERE specs->'spec_options' @> '["spec1", "spec2"]';
Run Code Online (Sandbox Code Playgroud)

我相信你可以转换成ActiveRecord兼容的语法,如下所示:

scope :with_spec_options, ->(spec_options) { 
  where("specs->'spec_option' @> ?", spec_options.to_json) 
}
Run Code Online (Sandbox Code Playgroud)

  • 抱歉,我的意思是:`where("specs->'spec_option' ?| array[:options]", options: spec_options)`。插入正确的 Postgres 语法有点棘手。 (2认同)