【问题标题】:Rails (postgres) query with jsonb array带有 jsonb 数组的 Rails (postgres) 查询
【发布时间】:2016-06-14 18:10:56
【问题描述】:

我的产品模型有一个 jsonb 字段 specs(我们使用 ActiveRecord 的 store_accessor 进行管理)。我的许多产品规范在该哈希中都有一个名为 spec_options 的规范。

在此之前,spec_option 字段只是文本。现在它需要是一个数组。

之前用于查询该字段的产品的范围是这样的:

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

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

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

ActiveRecord 等效项(如果 spec_option 是常规列):

where(spec_option: spec_options)

但是,既然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

有人有想法吗?

【问题讨论】:

    标签: ruby-on-rails postgresql activerecord jsonb


    【解决方案1】:

    您要使用的是@> operator,它测试您的左侧值是否包含右侧值。 “包含”适用于对象和数组,因此以下查询可以使用:

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

    我相信你可以像这样转换成与 ActiveRecord 兼容的语法:

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

    【讨论】:

    • 谢谢!差不多就是这样。操作的双方都需要jsonb,所以这个工作:where("specs->'spec_option' @> ?::jsonb", spec_options.to_json)
    • 废话,你不需要额外的 ::jsonb 转换:where("specs->'spec_option' @> ?", spec_options.to_json)
    • 呃,所以我认为这是一个解决方案,但这不是我需要的完全。如果 any 查询的选项匹配,则需要返回结果。此答案仅返回 all 匹配的结果。
    • @Obversity:试试这个:where("specs->'spec_option' ?| :options", options: spec_options).
    • 对不起,我的意思是:where("specs->'spec_option' ?| array[:options]", options: spec_options)。插入正确的 Postgres 语法有点棘手。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-29
    • 2015-11-28
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多