10

I'm using knex to generate my SQL queries. In knex documentation, it shows this

knex('users').where('columnName', 'like', '%rowlikeme%')

Now in my application, I did this:

function search(term) {
  term = "%" + term + "%";
  knex('table').where('description', 'like', term);
  // ...
}

How can I escape % so that it searches for % as part of the term as well?

Thanks.

coockoo
  • 2,294
  • 17
  • 26
Jun
  • 113
  • 1
  • 2
  • 7

10 Answers10

10

For this case I use

rather string interpolation from es6 (safe version)

knex('table').where('description', 'like', `%${term}%`)

or ?? parameter binding

knex('table').whereRaw('description like \'%??%\'', [term])

But in the first case, you must be 100% sure that term is valid, because of the possibility of SQL injection.

Sk1d
  • 17
  • 4
coockoo
  • 2,294
  • 17
  • 26
  • 4
    The _first_ example has the possibility of SQL injection. The second is using named parameters, so should be safe. – user5670895 May 08 '19 at 01:53
  • The first one does not work for me. When term is 'foo' the binding is 'undefinedfooundefined'. – Tim Scott Dec 05 '19 at 22:33
  • 1
    @user128216 Why is the first example `where('description', 'like', `%${term}%`)` prone sql injection? Isn't this as safe as the parameter binding? The ref link doesn't mention where being prone to sql injection, only raw. – SILENT Jan 08 '20 at 21:09
  • 8
    The term in a `.where` is escaped, so there's no risk of injection: https://github.com/knex/documentation/issues/73#issuecomment-572482153 – Loren Jan 09 '20 at 20:43
  • 3
    The second one is badly wrong and shouldn't work at all (`??` binding should be used only for identifiers, so if there is dot in `term` it will fail). First one should be fine except I have no idea if that actually is able to match `%` char. – Mikael Lepistö Jan 09 '20 at 23:45
5

So I was looking for a correct way to apply LOWER function to the parameter. Here's the solution that seems to be working fine for me:

builder.whereRaw('LOWER(last_name) LIKE LOWER(?)', [`%${lastName}%`])
Andrew Kicha
  • 143
  • 2
  • 6
2

@coockoo's answer is incorrect for both of the SQLs. Their first one would still allow % through as Knex does not escape % for LIKE operations. The second SQL simply does not work as Knex wraps the bound value with quotes.

The correct way should be

const term = '10%'
const b = knex('table').where('description', 'like', `%${term.replaceAll('%', '\\%')}%`)

The output of b.toString() is:

select * from "table" where "description" like E'%10\\%%'

Postgres will interpret E'\\%' as '\%', which is an escaped percentage sign according to: https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-LIKE by default if you are on newer Postgres version.


This can be verified with this table:

CREATE TABLE test (
    description character varying(256)
);

INSERT INTO test VALUES ('a%b');

and test the following:

  1. Without escaping % like others have suggested. This shouldn't work.
knex('test').where('description', 'like', 'a%%%b').toString()
select * from "test" where "description" like 'a%%%b'
 description
-------------
 a%b
(1 row)
  1. Escaping % before giving to Knex.

    1. This should return no rows:
    knex('test').where('description', 'like', 'a\\%\\%\\%b').toString()
    
    select * from "test" where "description" like E'a\\%\\%\\%b'
    
     description
    -------------
    (0 rows)
    
    1. This should return 'a%b':
    knex('test').where('description', 'like', 'a\\%b').toString()
    
    select * from "test" where "description" like E'a\\%b'
    
     description
    -------------
     a%b
    (1 row)
    

SQL Fiddle: http://sqlfiddle.com/#!17/d2f5e/1

Daniel Cheung
  • 4,779
  • 1
  • 30
  • 63
0

Use the RLIKE instead of LIKE as below, It should work for you.

function search(term){
    knex('table').where('description','rlike',term);
    ...
}
  • Hi, rlike didn't pass the test case. Example: Search term is "40%". Result should show: "Microscopic 40% Bacterialium", "40% Alcohol", "Creatine 40%" But it is not showing "Creatine 40%" and "Microscopic 40% Bacterialium". – Jun May 14 '18 at 09:39
  • Can you try papssing term once with " ` " as : knex('table').where('description','like',`term`); –  May 14 '18 at 09:44
  • If i add % before and after the term, it will reply all 3 three results. If I don't, it will return nothing while using like keyword. – Jun May 14 '18 at 09:47
  • Because, that is the rule of like. For example if you have a value like "World" and search for '%orl%' with like then it will return. but if you search for 'orl' with then it won't. Here '%' mean one or more character –  May 14 '18 at 09:50
0

Knex doesn't have an equivalent to the ESCAPE keyword [1], so you have to do a raw query like this, which will search for users with name === "%foo%":

knex.raw('select * from users where name like ? escape \', ['\%foo\%'])

And this, with an unescaped wildcard at the beginning of the search term, will search for users with name ending in "%foo%":

knex.raw('select * from users where name like ? escape \', ['%\%foo\%'])

[1] Closed feature request: https://github.com/knex/knex/issues/648

Loren
  • 13,903
  • 8
  • 48
  • 79
  • 1
    By reading SQL docs this kind of make sense and could work. Though `knex('users').whereRaw('?? like ? escape \\%, ['name', '%\\%foo%'])` might be more near to working solution. – Mikael Lepistö Jan 09 '20 at 23:50
0

whereILike

http://knexjs.org/guide/query-builder.html#whereilike

This is doc for this


knex('users').whereILike('email', '%mail%')

knex('users')
  .whereILike('email', '%MAIL%')
  .andWhereILike('email', '%.COM')
  .orWhereILike('email', '%NAME%')

0

For this to resolve you can add the search term in a separate variable and add % at the beginning and end of the string. For ex:

const likeParams = '%' + selectedKeyword + '%';
knex('users').where('title', 'ilike', likeParams);
0

I know this question is 2 years old, but reading the Knex documentation I found out they added a function for this scenario.

knex('users').whereLike('email', '%mail%');
-1

Hey have you tried this

knex('Quotes').where('quoteBody', 'like', **'%'+Quote+'%'**)

just the regular javascript escaping works just fine.

UserCah
  • 26
  • 3
-3

I have not used knex in a while so I can not test this. But have you tried to literally escape %? I hope that is what you want.

let term = "%something%"
let parsedTerm = term.replace("%", "\%")
console.log(parsedTerm);

Tell me about that please.

ShaH
  • 170
  • 1
  • 9