5

Я пытаюсь добавить частичный индекс в столбец postgresql jsonb. Столбец jsonb называется: email_provider. Я попытался добавить частичный индекс в столбце, как показано ниже, но он вызывает различную ошибку, подобную этому PG :: UndefinedColumn: ERROR: столбец «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')" 

JSON для столбца email_provider выглядит следующим образом:

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

Update

на основе незначительной корректировки принятого ответ ниже, код, я использую для создания ВТКЕГО не джина индекса в рельсах activerecord показано ниже. Это создает индекс ВТКЕЯ, потому что мы используем столбец имени, которое строковый типа данных и не jsonb, как описано here:

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

Я ve изменил второй аргумент add_index на :email_provider, потому что это имя столбца. Кроме того, для клаузулы о where, я изменил

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

в

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

, потому что оператор -> ожидает, что он оставил аргумент, чтобы быть в формате JSON (б) значение, но при условии, строки. Так, например, email_provider -> 'email_provider' извлекает значение, соответствующее email_provider, из столбца email_provider. Обратите внимание, что эта последняя линия может быть записана в более компактной форме как:

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

с помощью #>>, который выделяет «путь» из josn (б) объект. Таким образом, 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 будет ** провайдером электронной почты **, потому что запрос будет быстрее, когда индекс находится в столбце ** ** и ** где запрос ** используется для ограничения нашего индекса на соответствие столбцу 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' = ' www.sparkpost.com ') И (email_provider ->' email_povider '->' amazon ses '- >>' smtp_host '=' www.awses.com ') "**, который создает ** btree partial index ** в колонке ** name **, ограничивающей наши соответствия атрибутами в столбце jsonb. – brg

Смежные вопросы