Rails (postgres) 使用 jsonb 数组查询
Rails (postgres) query with jsonb array
我的产品模型有一个 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
有人有想法吗?
您要使用的是 @>
operator,它会测试您的左手值是否包含右手值。 "Contains" 适用于对象和数组,因此以下查询将有效:
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 字段 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
有人有想法吗?
您要使用的是 @>
operator,它会测试您的左手值是否包含右手值。 "Contains" 适用于对象和数组,因此以下查询将有效:
SELECT * FROM products WHERE specs->'spec_options' @> '["spec1", "spec2"]';
我相信您可以将其转换为与 ActiveRecord 兼容的语法,如下所示:
scope :with_spec_options, ->(spec_options) {
where("specs->'spec_option' @> ?", spec_options.to_json)
}