Search code examples
postgresqljsonbknex.js

Building knex innerJoin with Postgres JSONB "?" operator?


I want to create a query like this with knex:

select "data"."parent"."name"
from "data"."parent"
         inner join "data"."child" on child_hashes::jsonb ? "data"."child".hash
where "data"."child"."name" = 'Hans'

child_hashes is a JSON column that stores an ordered array with child hashes.

1. Normal query

knex
            .table(this.parentTableName)
            .innerJoin(this.childTableName, "child_hashes::jsonb", "?", `${this.childTableName}.hash`)
            .where(`${this.childTableName}.name`, name)
            .pluck(`${this.parentTableName}.name`);

this returns the "child_hashes::jsonb" in double quotes

select "data"."parent"."name"
from "data"."parent"
         inner join "data"."child" on "child_hashes::jsonb" ? "data"."child".hash
where "data"."child"."name" = 'Hans'

2. innerJoin with raw query in callback

knex
            .table(this.parentTableName)
            .innerJoin(this.childTableName, (query) => {
                query.on(this.knex.raw("child_hashes::jsonb ? ?.hash", ["?", this.childTableName]));
            })
            .where(`${this.childTableName}.name`, name)
            .pluck(`${this.parentTableName}.name`);

this returns the ? operator in single quotes

select "data"."parent"."name"
from "data"."parent"
         inner join "data"."child" on child_hashes::jsonb '?' "data"."child".hash
where "data"."child"."name" = 'Hans'

Edit: The second attempt also didn't work without the binding of this.childTableName. It uses "name" from the where clause below.


Solution

  • It worked after escaping the ? in the second query:

    knex
                .table(this.parentTableName)
                .innerJoin(this.childTableName, (query) => {
                    query.on(this.knex.raw("child_hashes::jsonb \\? ??.hash", [this.childTableName]));
                })
                .where(`${this.childTableName}.name`, name)
                .pluck(`${this.parentTableName}.name`);