Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to escape the ? (question mark) operator to query Postgresql JSONB type in Rails

Tags:

I'm working with Rails 4.2 and Postgres 9.4 to try out the new JSONB data type. One of the JSONB columns in my database holds an array, and I want to be able to query for records where this array contains a certain value. I figured out how to do this using the new JSONB "question mark" ("contains") operator, as documented here: http://www.postgresql.org/docs/9.4/static/functions-json.html

So in raw SQL I can get this to work as in this example:

SELECT * FROM people WHERE roles ? '32486d83-4a38-42ba-afdb-f77ca40ea1fc'; 

But I can't see any way to do this query from within Rails via ActiveRecord. I've tried doing a raw query using the "where" method, as follows:

Person.where("roles ? ?", "32486d83-4a38-42ba-afdb-f77ca40ea1fc") 

But since the question mark is a special character used to replace parameters, I get this error:

ActiveRecord::PreparedStatementInvalid: wrong number of bind variables (1 for 2) in: roles ? ?

I guess I need a way to escape the "?" character since I want it to pass through literally. I've tried \? and ?? with no luck. Any help is appreciated!

like image 920
dfinn Avatar asked Jun 03 '15 19:06

dfinn


People also ask

How do you escape a question mark in SQL query?

To keep such question marks in a SQL statement from being interpreted as positional parameters, use two question marks ( ?? ) as escape sequence. You can also use this escape sequence in a Statement , but that is not required. Specifically only in a Statement a single ( ? ) can be used as an operator.

What is Jsonb in SQL?

The JSONB data type stores JSON (JavaScript Object Notation) data as a binary representation of the JSONB value, which eliminates whitespace, duplicate keys, and key ordering. JSONB supports GIN indexes.


2 Answers

You should call this as below :

Person.where("roles ? :name", name: "32486d83-4a38-42ba-afdb-f77ca40ea1fc") 
like image 63
Arup Rakshit Avatar answered Oct 01 '22 03:10

Arup Rakshit


A workaround. Run this query to find out what function your operator maps to:

SELECT    oprname,    oprcode || '(' || format_type(oprleft,  NULL::integer) || ', '                   || format_type(oprright, NULL::integer) || ')' AS function FROM pg_operator  WHERE oprname = '?'; 

It yields

oprname  function ?        jsonb_exists(jsonb, text) ?        exist(hstore, text) 

Now use the function instead of the operator in your query:

Person.where("jsonb_exists(roles, ?)", "32486d83-4a38-42ba-afdb-f77ca40ea1fc") 
like image 32
Lukas Eder Avatar answered Oct 01 '22 03:10

Lukas Eder