为 postgresql jsonb 字段创建部分索引
Create partial index for postgresql jsonb field
我正在尝试将部分索引添加到 postgresql jsonb 列。 jsonb 列被命名为:email_provider。我尝试在列上添加部分索引,如下所示,但它会抛出不同的错误,例如 PG::UndefinedColumn: ERROR: column "email_povider" does not exist 和其他时候它引发错误:PG::AmbiguousFunction: ERROR: operator is not unique: unknown -> unknown
rails-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": " "
}
}
}
table 看起来像这样:
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 的代码不是 gin 在 [=47 中的索引=] activerecord 如下所示。它创建了一个 btree 索引,因为我们使用的是字符串数据类型 的 name 列,而不是 here 描述的 jsonb :
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"
我想你需要这样的东西:
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
的第二个参数更改为 :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) 对象中提取 "path" 的 #>>
。所以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
以获得所需的类型。
我正在尝试将部分索引添加到 postgresql jsonb 列。 jsonb 列被命名为:email_provider。我尝试在列上添加部分索引,如下所示,但它会抛出不同的错误,例如 PG::UndefinedColumn: ERROR: column "email_povider" does not exist 和其他时候它引发错误:PG::AmbiguousFunction: ERROR: operator is not unique: unknown -> unknown
rails-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": " "
}
}
}
table 看起来像这样:
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 的代码不是 gin 在 [=47 中的索引=] activerecord 如下所示。它创建了一个 btree 索引,因为我们使用的是字符串数据类型 的 name 列,而不是 here 描述的 jsonb :
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"
我想你需要这样的东西:
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
的第二个参数更改为 :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) 对象中提取 "path" 的 #>>
。所以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
以获得所需的类型。