我的Rails应用程序中有一些HStore列。查看Posgresql文档和some blog posts,我发现,给定一个像这样的哈希值的HStore值:
{ some_key: 'value' }
我可以像这样查询列:
Model.where("the_hstore_column -> 'some_key' = 'value'")
然而,作为一个充分的查询工具,存在许多问题:
这对超级简单的值来说真的很有意义。如果值是 本身就是哈希或其他东西,我不知道如何搜索它 如果我不知道它的所有内容,我会有效地。 (即使我做了,我也是 必须将它们全部转换为字符串化的JSON或其他东西)。
这样做有帮助(至少,我无法提供帮助) 查询列的内容是否存在(或 列下任意键的内容。
换句话说(在伪sql中),我希望能够做到这一点:
Model.where("the_hstore_column = {}")
Model.where.not("the_hstore_column = {}")
或者:
Model.where("the_hstore_column -> 'some_key' = NULL")
Model.where.not("the_hstore_column -> 'some_key' = NULL")
或者最好的是,给定HStore值{ some_key: { sub_key: 'value' } }
:
Model.where("the_hstore_column -> 'some_key' INCLUDES (?)", 'sub_key')
Model.where.not("the_hstore_column -> 'some_key' INCLUDES (?)", 'sub_key')
这些似乎不起作用,但对于我的生活,我无法找到有关如何进行这些查询的重要信息。有谁知道如何写它们,或者我可以在哪里寻找更好的信息?
更新经过多次回顾,我找到了this post,看起来很有前途,但我无法获得实际工作的代码。例如,Model.where("the_hstore_column ? :key", key: 'some_key')
返回空关系,即使Model
中有some_key
个the_hstore_column
个对象。
根据Andrius Buivydas的要求,我在下面粘贴了我的模型的相关部分。它相对简短,因为我决定将Hstore访问抽象到我编写的模块中,基本上把它变成一个哈希存储(我觉得,这显然是错误的,是它的全部目的)。我尝试使用内置的store_accessor
,但它并没有按照我的喜好工作,(似乎没有帮助解析已保存的哈希,因为现在显而易见的原因)因此{{1下面的模块。 (ActiveRecord::MetaExt::HstoreAccessor
只接受一个HStore字符串并将其解析为哈希)。
ParsedHstore
(在另一个文件中):
class Place.rb
include ActiveRecord::MetaExt::HstoreAccessor
hstore_accessor :hours, :extra
end
这个想法是,这让我可以轻松地向HStore字段添加/删除值,而无需每次都考虑合并和module ActiveRecord
module MetaExt
module HstoreAccessor
module ClassMethods
def hstore_accessor(*symbols)
symbols.each do |field|
class_eval do
define_method(field) do
ParsedHstore.new(self[field.to_sym]).hash_value
end
define_method("add_to_#{field}!") do |arg|
self[field.to_sym] = self[field.to_sym].merge(arg)
send("#{field}_will_change!")
save
arg
end
define_method("add_to_#{field}") do |arg|
self[field.to_sym] = self[field.to_sym].merge(arg)
send("#{field}_will_change!")
arg
end
define_method("remove_from_#{field}") do |arg|
other = self[field].dup
other.delete(arg.to_s); other.delete(arg.to_sym)
self[field.to_sym] = other
send("#{field}_will_change!")
self[field.to_sym]
end
define_method("remove_from_#{field}!") do |arg|
other = self[field].dup
other.delete(arg.to_s); other.delete(arg.to_sym)
self[field.to_sym] = other
send("#{field}_will_change!")
save
self[field.to_sym]
end
define_method("set_#{field}") do |arg|
self[field.to_sym] = arg
send("#{field}_will_change!")
self[field.to_sym]
end
define_method("set_#{field}!") do |arg|
self[field.to_sym] = arg
send("#{field}_will_change!")
self[field.to_sym]
end
end
end
end
end
def self.included(base)
base.extend ClassMethods
end
end
end
end
逻辑。所以我可以这样做,例如:_will_change!
。
我应该制作这些字段
Place.first.add_to_extra({ key: 'value'})
还是json
?我觉得我在这里重新发明轮子,或者更恰当地说,试图将一匹马变成一个轮子或什么的。
另外,我可能误解了查询示例。我确实在我的数据库中尝试了这个查询(在jsonb
字段下有许多非空ranking
键的地方),并且显示为空关系:
extra
如果我搞砸了这种语法,我不会感到惊讶,因为它看起来很奇怪。不会将Place.where("extra ? :key", key: 'ranking')
替换为?
,将查询转换为此内容?:'ranking'
?看起来很怪异,并且与我运行的任何其他SQL有着明显的不同。还是转向Place.where("extra ranking :key")
?但Place.where("extra ? ranking")
通常用于安全注入变量,不是吗?
如果我的模型或其他地方的其他内容更具相关性,请告诉我。
答案 0 :(得分:1)
这对超级简单的值来说真的很有意义。如果这个值本身就是一个哈希值,我不知道如何有效地搜索它,如果我不知道它的所有内容。
Postgresql HStore仅存储两个字符串的键值对。因此,您无法存储散列,零或其他类似对象的东西 - 它们将被转换为字符串。
Model.where(" the_hstore_column?:key",key:' some_key')
如果一切都正确定义,这应该有用。您可以使用hstore列值的定义粘贴模型文件的摘录吗?
答案 1 :(得分:0)
查找空hstore列的另一种方法是
Model.where(hstore_column: ['',nil])
OR
Model.where("hstore_column='' OR hstore_column IS NULL")