2016-09-23 37 views
5

我想向postgresql jsonb列添加部分索引。 jsonb列被命名爲:email_provider。我曾嘗試在列上添加一個部分索引,但它會拋出不同的錯誤,如下所示PG :: UndefinedColumn:錯誤:列「email_povider」不存在並在其他時間引發錯誤:PG :: AmbiguousFunction :錯誤:操作者不是唯一的:未知 - >未知爲postgresql jsonb字段創建部分索引

局部索引在導軌-5遷移看起來像這樣:

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看起來像這樣:

{ 
    "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 

更新

基礎上稍作調整下面的接受的答案,代碼我使用創造B樹沒有杜松子酒指數在rails中activerecord如下所示。

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

我想你需要類似的東西:

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')" 

我,因爲我們使用的是name列是字符串數據類型的,而不是作爲描述here jsonb創建一個B樹索引已將add_index的第二個參數更改爲:email_provider,因爲這是列名稱。此外,對於該where條款,我改變

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

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

因爲->運營商期望它離開的說法是一個JSON(B)值,但提供的字符串。所以例如email_provider -> 'email_provider'從名爲email_provider的列中提取對應於email_provider的值。注意,這最後的線可被更緊湊地寫爲:

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

通過使用從josn(b)中的對象提取的「路徑」的#>>。所以add_index語句可以寫爲:

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')" 

關於第二個索引,你應該嘗試這樣的:

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

在這種情況下,我也同樣認爲與列第一案件。我還更改了@>的正確參數,該參數必須是jsonb值。所以你必須將它定義爲JSON字符串,它需要字符串的雙引號(還要注意,我們必須將它們轉義爲ruby),然後我將該字符串轉換爲jsonb以獲得所需的類型。

+0

謝謝,我會嘗試一下並回復你。但是,儘管jsonb列是**電子郵件提供商**,我很可能會將索引放置在**名稱列**,因爲當索引位於**名稱列**和**其中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'=' ')和(email_provider - >'email_povider' - >'amazon ses' - >>'smtp_host'='www.awses.com')「**,這會創建一個** btree部分索引**在**名稱列** **限制我們的匹配到jsonb列中的屬性。 – brg