2016-09-23 64 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