简体   繁体   English

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

[英]Rails (postgres) query with jsonb array

My Product model has a jsonb field specs (which we're managing using ActiveRecord's store_accessor ). 我的产品模型有一个jsonb字段specs (我们使用ActiveRecord的store_accessor管理)。 Many of my products' specs have a spec in that hash called spec_options . 我的许多产品的规格都有一个名为spec_options散列规范。

Before now, this spec_option field was just text. 在此之前,此spec_option字段只是文本。 Now it needs to be an array. 现在它需要是一个数组。

The scope used before now to query products for this field was this: 之前用于查询此字段的产品的范围是:

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

Ruby equivalent (just to help understand what this is doing): Ruby等价物(只是为了帮助理解这是做什么):

select{ |product| spec_options.include?(product.specs['spec_option']) }

ActiveRecord equivalent (if spec_option were a regular column): ActiveRecord等价物(如果spec_option是常规列):

where(spec_option: spec_options)

However, now that specs['spec_options'] is an array, I can't do that. 但是,既然specs['spec_options']是一个数组,我不能这样做。 I think I need to use postgres' ?| 我想我需要使用postgres' ?| jsonb operator, but I can't work out how to get the right side of this operation into the correct format. jsonb运算符,但我无法弄清楚如何将此操作的右侧转换为正确的格式。

Ruby equivalent: 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

Anyone got ideas? 有人有想法吗?

What you want to use is the @> operator , which tests whether your left-hand value contains the right-hand value. 你想要使用的是@>运算符 ,它测试你的左手值是否包含右手值。 "Contains" works for both objects and arrays, so the following query would work: “包含”适用于对象和数组,因此以下查询将起作用:

SELECT * FROM products WHERE specs->'spec_options' @> '["spec1", "spec2"]';

Which I believe you can transform into ActiveRecord-compatible syntax like so: 我相信你可以转换成ActiveRecord兼容的语法,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM