1

The desired MySQL query:

SELECT
  *
FROM
  myTable
WHERE 
  (
    JSON_CONTAINS(access,'"a"','$.owner') OR
    JSON_CONTAINS(access,'"b"','$.owner')
  ) AND
  (
    JSON_CONTAINS(access,'"c"','$.moderator') OR
    JSON_CONTAINS(access,'"d"','$.moderator')
  )

A snippet of some of the logic that dynamically builds the filters:

const args = {x: ["a", "b"], y: ["c", "d"]}
let where = {}
// more code
if (args.x && Array.isArray(args.x)) {
  const orWhere = args.x.map(x => sequelize.fn('JSON_CONTAINS', sequelize.col('access'), `"${x}"`,'$.owner'))
  where = {
    ...where,
    [Op.or]: orWhere
  }
}
if (args.y && Array.isArray(args.y)) {
  const orWhere = args.y.map(y => sequelize.fn('JSON_CONTAINS', sequelize.col('access'), `"${y}"`,'$.moderator'))
  where = {
    ...where,
    [Op.or]: orWhere
  }
}
// more code
db.contacts.findAll({where})

The problem with doing this is that when args.x and args.y are both provided then the [Op.or]: orWhere from the second statement overrides what is already in the where object.

I have read through the Sequelize WHERE docs, but have yet to find a solution. It would be simple if I was not doing complex JSON query functions.

NOTE: Yes, I am preventing against injection but that part is left out intentionally to shorten the code

EDIT: as @Anatoly suggested, use sequelize.fn instead of literal, but left with the same condition of overwriting where[Op.or] in second if condition

2
  • Didn't you try something like sequelize.fn('JSON_CONTAINS', sequelize.col('access'), '"a"','$.owner')? Commented May 18, 2020 at 22:36
  • @Anatoly, that would replace the literal(...) but still not solve the problem. I will update it with your recomendation. Commented May 18, 2020 at 22:39

1 Answer 1

3

You can use [Op.and] with a array of conditions just like you did with [Op.or]:

if ((args.x && Array.isArray(args.x)) ||
    (args.y && Array.isArray(args.y))) {
  where[Op.and] = []
  if (args.x && Array.isArray(args.x)) {
    const orWhere = args.x.map(x => sequelize.fn('JSON_CONTAINS',   sequelize.col('access'), `"${x}"`,'$.owner'))
    where[Op.and].push({
      [Op.or]: orWhere
    })
  }
  if (args.y && Array.isArray(args.y)) {
    const orWhere = args.y.map(y => sequelize.fn('JSON_CONTAINS', sequelize.col('access'), `"${y}"`,'$.moderator'))
    where[Op.and].push({
      [Op.or]: orWhere
    })
  }
}

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

1 Comment

That should do it... I will test it here soon. I don't know why it was so hard for me to get to that point

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.