whithang
whithang

Reputation: 37

Using Bookshelf to execute a query on Postgres JSONB array elements

I have a postgres table with jsonb array elements and I'm trying to do sql queries to extract the matching elements. I have the raw SQL query running from the postgres command line interface:

select * from movies where director @> any (array ['70', '45']::jsonb[])

This returns the results I'm looking for (all records from the movies table where the director jsonb elements contain any of the elements in the input element).

In the code, the value for ['70, '45'] would be a dynamic variable ie. fixArr and the length of the array is unknown.

I'm trying to build this into my Bookshelf code but haven't been able to find any examples that address the complexity of the use case. I've tried the following approaches but none of them work:

models.Movies.where('director', '@> any', '(array' +  JSON.stringify(fixArr) + '::jsonb[])').fetchAll()
ERROR: The operator "@> any" is not permitted

db.knex.raw('select * from movies where director @> any(array'+[JSON.stringify(fixArr)]+'::jsonb[])')
ERROR: column "45" does not exist

models.Movies.query('where', 'director', '@>', 'any (array', JSON.stringify(fixArr) + '::jsonb[])').fetchAll()
ERROR: invalid input syntax for type json

Can anyone help with this?

Upvotes: 2

Views: 1267

Answers (2)

jnj16180340
jnj16180340

Reputation: 61

No, you're just running into the limitations of that particular query builder and ORM.

The easiest way is using bookshelf.Model.query and knex.raw (whereRaw, etc.). Alias with AS and subclass your Bookshelf model to add these aliased attributes if you care about such things.

If you want things to look clean and abstracted through Bookshelf, you'll just need to denormalize the JSONB into flat tables. This might be the best approach if your JSONB is mostly flat and simple.

If you end up using lots of JSONB (it can be quite performant with appropriate indexes) then Bookshelf ORM is wasted effort. The knex query builder is only not a waste of time insofar as it handles escaping, quoting, etc.

Upvotes: 0

Mikael Lepistö
Mikael Lepistö

Reputation: 19728

As you have noticed, knex nor bookshelf doesn't bring any support for making jsonb queries easier. As far as I know the only knex based ORM that supports jsonb queries etc. nicely is Objection.js

In your case I suppose better operator to find if jsonb column contains any of the given values would be ?|, so query would be like:

const idsAsString = ids.map(val => `'${val}'`).join(',');
db.knex.raw(`select * from movies where director \\?| array[${idsAsString}]`);

More info how to deal with jsonb queries and indexing with knex can be found here https://www.vincit.fi/en/blog/objection-js-postgresql-power-json-queries/

Upvotes: 0

Related Questions