2016-09-23 21 views
5

postgresql jsonbカラムに部分インデックスを追加しようとしています。 jsonb列の名前は、email_providerです。私は以下のように列に部分的なインデックスを追加しようとしましたが、このように異なるエラーが発生しますPG :: UndefinedColumn:ERROR:列 "email_povider"が存在しませんと、それ以外の時にエラーを発生させます:PG :: AmbiguousFunction :ERROR:オペレータがユニークではありません: - :postgresql jsonbフィールドの部分インデックスを作成します。

add_index :accounts, :name, name: "index_accounts_on_email_provider_kind", using: :gin, where: "('email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com') AND ('email_povider' -> 'amazon ses' ->> 'smtp_host' = 'www.awses.com')" 

email_provider列のJSONは次のようになります。

不明レール-5移行は次のようになりますで>不明

部分インデックス

{ 
    "email_provider": { 
    "sparkpost": { 
     "smtp_host": "www.sparkpost.com", 
     "smtp_port": "" 
     }, 
     "aws ses": { 
     "smtp_host": "www.amazon/ses.com ", 
     "smtp_port": " ", 
     "username": " ", 
     "password": " " 
     } 
    } 
} 

テーブルは次のようになります。

class CreateAccounts < ActiveRecord::Migration[5.0] 
    def change 
     create_table :accounts do |t| 
     t.string :name, null: false 
     t.jsonb :email_provider, null: false 
     t.jsonb :social_account, default: '[]', null: false 
     t.timestamps 
    end 
     add_index :accounts, :name, name: "index_accounts_on_email_provider_kind", using: :gin, where: "('email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com') AND ('email_povider' -> 'amazon ses' ->> 'smtp_host' = 'www.awses.com')" 

     add_index :accounts, :name, name: "index_accounts_on_social_account_type", using: :gin, where: " 'social_account' @> [{'type': 'facebook'}] AND 'social_account' @> [{'type': 'twitter'}]" 
    end 
end 

更新以下受け入れ答えに微調整、私はBTREEないジンインデックスを作成するために使用していたコードに基づいて

in rails activerecordを以下に示します。私は「

add_index :accounts, :email_provider, name: "index_accounts_on_email_provider_kind", using: :gin, where: "(email_provider -> 'email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com') AND (email_provider -> 'email_povider' -> 'amazon ses' ->> 'smtp_host' = 'www.awses.com')" 

add_index :accounts, :name, name: "index_accounts_on_name_email_provider", where: "email_provider -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com' AND email_provider -> 'amazon ses' ->> 'smtp_host' = 'www.awses.com' " 

add_index :accounts, :name, name: "index_accounts_on_name_social_account", where: " social_account @> '[{\"type\": \"facebook\"}]'::jsonb AND social_account @> '[{\"type\": \"twitter\"}]'::jsonb" 

答えて

9

私はあなたがそのようなものが必要だと思う:私たちは文字列データ型であり、hereが説明するようにjsonbない名前の欄を使用しているので、それはBTREEインデックスを作成しますadd_indexの2番目の引数を:email_providerに変更しました。これはその列名です。また、where句のために、私は

email_provider -> 'email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com' 

->オペレータが、それはJSON(b)の値になるように引数を左に期待しているため

'email_provider' -> 'sparkpost' ->> 'smtp_host' = 'www.sparkpost.com' 

を変更していますが、文字列を提供します。だからemail_provider -> 'email_provider'email_providerという列からemail_providerに対応する値を抽出します。 josn(b)は、オブジェクトからの「パス」を抽出#>>を用いて

email_provider #>> '{email_provider,sparkpost,smtp_host}' = 'www.sparkpost.com' 

:この最後の行は、よりコンパクトに書くことができることに留意されたいです。 2番目のインデックスあなたのために

add_index :accounts, :email_provider, name: "index_accounts_on_email_provider_kind", using: :gin, where: "(email_provider #>> '{email_provider,sparkpost,smtp_host}' = 'www.sparkpost.com') AND (email_provider -> '{email_povider,amazon ses,smtp_host}' = 'www.awses.com')" 

、あなたのような何かを試してみてください::だからadd_indexステートメントは、のように記述することができる。この場合、

where: " social_account -> 'social_account' @> '[{\"type\": \"facebook\"}]'::jsonb AND social_account -> 'social_account' @> '[{\"type\": \"twitter\"}]'::jsonb" 

を、私は同じことが最初のように列に思いました場合。私は@>の右の引数も変更しました。これはjsonbの値でなければなりません。だからJSON文字列として定義する必要があります。これは文字列の二重引用符を必要とします(rubyのためにそれらをエスケープする必要があることに注意してください)。そして、その文字列をjsonbにキャストして目的のタイプを取得します。

+0

ありがとう、私はこれを試して、あなたに戻ってきます。ただし、** name列**にインデックスを配置する可能性が最も高いのは、jsonb列が**電子メールプロバイダ**であっても**インデックスが** name列**にあり、** query **はインデックスをjsonb列からの一致に制限するために使用されます。このアプローチはhttp://blog.heapanalytics.com/speeding-up-postgresql-queries-with-partial-indexes/で説明されています。 – brg

+0

多くのありがとうございます。私はインデックスを**名前列**に置いていました。唯一の変更は**::: gin **を使用してインデックスを削除することでした。なぜなら、インデックスはjsonbの列に直接ないからです。 ** add_index:accounts、:name、name: "index_accounts_on_name_email_provider"ここで、 "(email_provider - > 'email_provider' - > 'sparkpost' - > 'smtp_host' = ' ** btree部分インデックスを作成する**(email_provider - > 'email_povider' - > 'amazon ses' - >> 'smtp_host' = 'www.awses.com') "** ** name列**で、一致をjsonb列の属性に限定します。 – brg

関連する問題