Rails / Postgres查询Hstore是否存在

时间:2015-01-23 16:06:59

标签: ruby-on-rails postgresql activerecord postgresql-9.2 hstore

我的Rails应用程序中有一些HStore列。查看Posgresql文档和some blog posts,我发现,给定一个像这样的哈希值的HStore值:

{ some_key: 'value' }

我可以像这样查询列:

Model.where("the_hstore_column -> 'some_key' = 'value'")

然而,作为一个充分的查询工具,存在许多问题:

  1. 这对超级简单的值来说真的很有意义。如果值是 本身就是哈希或其他东西,我不知道如何搜索它 如果我不知道它的所有内容,我会有效地。 (即使我做了,我也是 必须将它们全部转换为字符串化的JSON或其他东西)。

  2. 这样做有帮助(至少,我无法提供帮助) 查询列的内容是否存在(或 列下任意键的内容。

  3. 换句话说(在伪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_keythe_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")通常用于安全注入变量,不是吗?

    如果我的模型或其他地方的其他内容更具相关性,请告诉我。

2 个答案:

答案 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")