Создать объединенный индекс для столбца JSONB в PostgreSQL

Мне нужно установить комбинированный индекс для двух полей из JSONB в моей базе данных PostgreSQL. Я могу установить индекс для одного поля следующим образом (используя ActiveRecord в моем приложении на Rails 6):

add_index :my_table,
  "(content->'reference')",
  using: :gin,
  name: 'index_my_table_on_content_reference'

Этот работает как ожидалось. Однако, когда я пытаюсь установить комбинированный индекс для двух полей, я получаю следующую ошибку:

add_index :my_table, 
  ["(content->'reference')", "(content->'ext_id')"], 
  using: :gin,
  name: 'index_my_table_on_content_ref_and_ext_id'
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column "(content->'reference')" does not exist

Что я делаю не так и как я могу создать комбинированный индекс для нескольких полей в столбце JSONB?

И прежде чем спросить: да, у каждого BLOB-объекта JSONB есть ключ с именем reference .

Использование: Ruby 2.6.5, Rails 6.0, PostgreSQL 11

Всего 2 ответа


Ошибка PG::UndefinedColumn: ERROR: column "(content->'reference')" does not exist значит, он обрабатывает "(content->'reference')" как имя столбца.

Воспроизведение из SQL:

create index my_table_json_idx on my_table using gin(
   (content->'reference'),
   "(content->'ext_id')"
);

Обратите внимание на кавычки вокруг второго выражения.

Кажется, есть проблема с вашей библиотекой ActiveRecord, и она экранирует ваше выражение jsonb, когда это нежелательно.

Либо используйте обычный SQL, либо попытайтесь заставить библиотеку ActiveRecord не экранировать выражение.

После некоторого поиска в Google я думаю, что изменение массива на строку "(content->'reference'), (content->'ext_id')" может сработать.


Ya Rails не знает, как вывести свой индекс jsonb, используя ruby. Таким образом, SQL будет способом пойти. Это была очень хорошая статья для меня, когда я начал возиться с jsonb Rails & jsonb

def change
  reversible do |dir|
    dir.up do 
      execute <<-SQL
       CREATE INDEX IF NOT EXISTS idx_my_table_on_content_references on my_table using gin ((content->>'reference'));
      SQL
    end

    dir.down {execute "DROP INDEX IF EXISTS idx_my_table_on_content_references;"}
  end
end

Есть идеи?

10000