2

I need to set a combined index on two fields from a JSONB in my PostgreSQL DB. I can set an index for a single field like so (using ActiveRecord in my Rails 6 application):

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

This one works as expected. However, when I try to set a combined index for two fields, I get the following error:

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

What am I doing wrong and how can I create a combined index for multiple fields in a JSONB column?

And before you ask: Yes, each JSONB blob has a key named reference.

Using: Ruby 2.6.5, Rails 6.0, PostgreSQL 11

4
  • PG gives this error when the entire expression is escaped and treated like a column name. create index my_table_json_idx on my_table using gin((content->'reference'), "(content->'ext_id')");. Seems there is problem with ActiveRecord escaping when it isn't desirable. Commented Mar 26, 2020 at 10:08
  • @Jindra Thx for your feedback. So your suggestion would be to write the migration in plain SQL? Commented Mar 26, 2020 at 10:15
  • I do not know Ruby On Rails or your ActiveRecord library so I can't really help you there. Maybe there is a way to tell it to not escape. If there isn't then plain SQL. Commented Mar 26, 2020 at 10:18
  • @Jindra I ended up using plain SQL. If you want please post your suggestion as answer. Commented Mar 26, 2020 at 10:50

2 Answers 2

1

The error PG::UndefinedColumn: ERROR: column "(content->'reference')" does not exist means it's treating "(content->'reference')" as a column name.

Reproducing from SQL:

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

Note the quotes around the second expression.

It seems there is a problem with your ActiveRecord library and it is escaping your jsonb expression when it isn't desirable.

Either use plain SQL or try to make your ActiveRecord library not escape your expression.

After some Googling I think changing the array to string "(content->'reference'), (content->'ext_id')" might work.

Sign up to request clarification or add additional context in comments.

Comments

0

Ya Rails doesn't know how to dump your jsonb index using ruby. So SQL would be the way to go. This was a pretty good article for me when I started messing with 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

2 Comments

This doesn't create a combined index, but I still see what you are getting at. Thx.
You may be able to create the clustered index the same way you do with regular columns. ((content->>'reference'), (content->>'ext_id'))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.