简体   繁体   English

Rails / Postgres查询Hstore是否存在

[英]Rails/Postgres query Hstore for presence

I have some HStore columns in my Rails app. 我的Rails应用程序中有一些HStore列。 Looking around the Posgresql documentation and some blog posts , I've discovered that, given an HStore value that is a hash like this: 查看Posgresql文档和一些博客文章 ,我发现,给定一个像这样的哈希值的HStore值:

{ some_key: 'value' }

I can query the columns like so: 我可以这样查询列:

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

There are a bunch of issues with this as a sufficient querying tool, however: 但是,作为一个充分的查询工具,有很多问题:

  1. It really only makes sense for super simple values. 它真的只对超级简单的值有意义。 If the value is itself a hash or something, I have no idea how to search for it effectively, if I don't know all its contents. 如果值本身就是哈希或其他东西,我不知道如何有效地搜索它,如果我不知道它的所有内容。 (Even if I did, I'd have to turn them all to stringified JSON or something). (即使我这样做了,我也必须将它们全部转换为字符串化的JSON或其他东西)。

  2. It isn't helpful (at least, I can't make it helpful) for doing queries for the presence or non-presence of the column's content (or the content of any key under the column). 对列的内容(或列下任何键的内容)的存在或不存在进行查询是没有用的(至少,我无法提供帮助)。

In other words (in pseudo-sql), I'd love to be able to do this: 换句话说(在伪sql中),我希望能够做到这一点:

Model.where("the_hstore_column = {}")
Model.where.not("the_hstore_column = {}")

Or: 要么:

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

Or best yet, given an HStore of value { some_key: { sub_key: 'value' } } : 或者最好的是,给定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')

These appear not to be working, but for the life of me, I can't find great information on how to conduct these queries. 这些似乎不起作用,但对于我的生活,我找不到有关如何进行这些查询的重要信息。 Does anyone know how to write them, or where I could look for better information? 有谁知道如何写它们,或者我可以在哪里寻找更好的信息?

UPDATE After more looking around, I found this post , which looked promising, but I can't get the code to actually work. 更新在更多的环顾之后,我发现这篇文章看起来很有前景,但我无法让代码真正起作用。 For example Model.where("the_hstore_column ? :key", key: 'some_key') is returning an empty relation, even if there are many Model objects with some_key in the_hstore_column . 例如Model.where("the_hstore_column ? :key", key: 'some_key')将返回一个空的关系,即使有许多Model与对象some_keythe_hstore_column

As requested by Andrius Buivydas , I'm pasting the relevant portion of my model below. 根据Andrius Buivydas的要求 ,我正在粘贴下面模型的相关部分。 It's relatively brief, because I decided to abstract out the Hstore-accessing into a module I wrote, essentially turning it into a hash store (which I though, apparently incorrectly, was its whole purpose). 这是相对简短的,因为我决定抽象出Hstore访问我写的模块,基本上把它变成一个哈希存储(我觉得,显然不正确,是它的整个目的)。 I tried using the built-in store_accessor , but it didn't work to my liking, (didn't seem to help parse saved hashes, for now obvious-seeming reasons) thus the ActiveRecord::MetaExt::HstoreAccessor module below. 我尝试使用内置的store_accessor ,但它并不符合我的喜好,(似乎没有帮助解析保存的哈希,现在看似明显的原因)因此下面的ActiveRecord::MetaExt::HstoreAccessor模块。 ( ParsedHstore just takes an HStore string and parses it into a hash). ParsedHstore只接受一个HStore字符串并将其解析为哈希)。

class Place.rb

  include ActiveRecord::MetaExt::HstoreAccessor
  hstore_accessor :hours, :extra

end

(In a separate file): (在单独的文件中):

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

The idea is that this lets me easily add/remove values to an HStore field, without having to think about the merging and _will_change! 这个想法是,这让我可以轻松地向HStore字段添加/删除值,而无需考虑合并和_will_change! logic every time. 逻辑每一次。 So I could do this, for example: Place.first.add_to_extra({ key: 'value'}) . 所以我可以这样做,例如: Place.first.add_to_extra({ key: 'value'})

Should I have made these fields json or jsonb ? 我应该制作这些字段json还是jsonb I feel like I'm reinventing the wheel here, or, more aptly, trying to turn a horse into a wheel or something. 我觉得我在这里重新发明轮子,或者更恰当地说,试图将马变成轮子或其他东西。

Also, I may be misunderstanding the query example. 另外,我可能误解了查询示例。 I literally tried this query in my database (which has many places with a non-empty ranking key under the extra field), and turned up with an empty relation: 我确实在我的数据库中尝试了这个查询(在extra字段下有许多非空ranking键的地方),并且显示为空关系:

Place.where("extra ? :key", key: 'ranking')

I wouldn't be surprised if I messed this syntax up, as it seems really strange. 如果我把这个语法搞砸了,我不会感到惊讶,因为它看起来很奇怪。 Wouldn't that replace the ? 那会不会取代? with 'ranking' , turning the query into this?: Place.where("extra ranking :key") ? 使用'ranking' ,将查询转换为这个?: Place.where("extra ranking :key") Seems weird and emphatically different from any other SQL I've run. 看起来很奇怪,并且与我运行的任何其他SQL强烈不同。 Or is it turning to Place.where("extra ? ranking") ? 或者它转向Place.where("extra ? ranking") But ? 但是? is usually for safe injection of variables, no? 通常用于安全注入变量,不是吗?

Please let me know if something else in my model or elsewhere would be more relevant. 如果我的模型或其他地方的其他内容更具相关性,请告诉我。

It really only makes sense for super simple values. 它真的只对超级简单的值有意义。 If the value is itself a hash or something, I have no idea how to search for it effectively, if I don't know all its contents. 如果值本身就是哈希或其他东西,我不知道如何有效地搜索它,如果我不知道它的所有内容。

Postgresql HStore stores key, values pairs that are both strings, only. Postgresql HStore仅存储两个字符串的键值对。 So you can't store a hash, a nil or something else like an object - they will be converted to the strings. 因此,您不能存储散列,零或其他类似对象的东西 - 它们将被转换为字符串。

Model.where("the_hstore_column ? :key", key: 'some_key') Model.where(“the_hstore_column?:key”,key:'some_key')

That should work if everything is defined correctly. 如果一切都正确定义,这应该工作。 Could you paste an extract of the model file with the definition of the hstore column values? 您可以使用hstore列值的定义粘贴模型文件的摘录吗?

Another way to find empty hstore columns is 查找空hstore列的另一种方法是

Model.where(hstore_column: ['',nil]) 

OR 要么

Model.where("hstore_column='' OR hstore_column IS NULL")

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

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