Where

Whether you are querying with findAll/find or doing bulk updates/destroys you can pass a where object to filter the query.

where generally takes an object from attribute:value pairs, where value can be primitives for equality matches or keyed objects for other operators.

It's also possible to generate complex AND/OR conditions by nesting sets of or and and Operators.

Basics

  1. const Op = Sequelize.Op;
  2. Post.findAll({
  3. where: {
  4. authorId: 2
  5. }
  6. });
  7. // SELECT * FROM post WHERE authorId = 2
  8. Post.findAll({
  9. where: {
  10. authorId: 12,
  11. status: 'active'
  12. }
  13. });
  14. // SELECT * FROM post WHERE authorId = 12 AND status = 'active';
  15. Post.findAll({
  16. where: {
  17. [Op.or]: [{authorId: 12}, {authorId: 13}]
  18. }
  19. });
  20. // SELECT * FROM post WHERE authorId = 12 OR authorId = 13;
  21. Post.findAll({
  22. where: {
  23. authorId: {
  24. [Op.or]: [12, 13]
  25. }
  26. }
  27. });
  28. // SELECT * FROM post WHERE authorId = 12 OR authorId = 13;
  29. Post.destroy({
  30. where: {
  31. status: 'inactive'
  32. }
  33. });
  34. // DELETE FROM post WHERE status = 'inactive';
  35. Post.update({
  36. updatedAt: null,
  37. }, {
  38. where: {
  39. deletedAt: {
  40. [Op.ne]: null
  41. }
  42. }
  43. });
  44. // UPDATE post SET updatedAt = null WHERE deletedAt NOT NULL;
  45. Post.findAll({
  46. where: sequelize.where(sequelize.fn('char_length', sequelize.col('status')), 6)
  47. });
  48. // SELECT * FROM post WHERE char_length(status) = 6;

Operators

Sequelize exposes symbol operators that can be used for to create more complex comparisons -

  1. const Op = Sequelize.Op
  2. [Op.and]: [{a: 5}, {b: 6}] // (a = 5) AND (b = 6)
  3. [Op.or]: [{a: 5}, {a: 6}] // (a = 5 OR a = 6)
  4. [Op.gt]: 6, // > 6
  5. [Op.gte]: 6, // >= 6
  6. [Op.lt]: 10, // < 10
  7. [Op.lte]: 10, // <= 10
  8. [Op.ne]: 20, // != 20
  9. [Op.eq]: 3, // = 3
  10. [Op.is]: null // IS NULL
  11. [Op.not]: true, // IS NOT TRUE
  12. [Op.between]: [6, 10], // BETWEEN 6 AND 10
  13. [Op.notBetween]: [11, 15], // NOT BETWEEN 11 AND 15
  14. [Op.in]: [1, 2], // IN [1, 2]
  15. [Op.notIn]: [1, 2], // NOT IN [1, 2]
  16. [Op.like]: '%hat', // LIKE '%hat'
  17. [Op.notLike]: '%hat' // NOT LIKE '%hat'
  18. [Op.iLike]: '%hat' // ILIKE '%hat' (case insensitive) (PG only)
  19. [Op.notILike]: '%hat' // NOT ILIKE '%hat' (PG only)
  20. [Op.startsWith]: 'hat' // LIKE 'hat%'
  21. [Op.endsWith]: 'hat' // LIKE '%hat'
  22. [Op.substring]: 'hat' // LIKE '%hat%'
  23. [Op.regexp]: '^[h|a|t]' // REGEXP/~ '^[h|a|t]' (MySQL/PG only)
  24. [Op.notRegexp]: '^[h|a|t]' // NOT REGEXP/!~ '^[h|a|t]' (MySQL/PG only)
  25. [Op.iRegexp]: '^[h|a|t]' // ~* '^[h|a|t]' (PG only)
  26. [Op.notIRegexp]: '^[h|a|t]' // !~* '^[h|a|t]' (PG only)
  27. [Op.like]: { [Op.any]: ['cat', 'hat']}
  28. // LIKE ANY ARRAY['cat', 'hat'] - also works for iLike and notLike
  29. [Op.overlap]: [1, 2] // && [1, 2] (PG array overlap operator)
  30. [Op.contains]: [1, 2] // @> [1, 2] (PG array contains operator)
  31. [Op.contained]: [1, 2] // <@ [1, 2] (PG array contained by operator)
  32. [Op.any]: [2,3] // ANY ARRAY[2, 3]::INTEGER (PG only)
  33. [Op.col]: 'user.organization_id' // = "user"."organization_id", with dialect specific column identifiers, PG in this example
  34. [Op.gt]: { [Op.all]: literal('SELECT 1') }
  35. // > ALL (SELECT 1)

Range Operators

Range types can be queried with all supported operators.

Keep in mind, the provided range value candefine the bound inclusion/exclusionas well.

  1. // All the above equality and inequality operators plus the following:
  2. [Op.contains]: 2 // @> '2'::integer (PG range contains element operator)
  3. [Op.contains]: [1, 2] // @> [1, 2) (PG range contains range operator)
  4. [Op.contained]: [1, 2] // <@ [1, 2) (PG range is contained by operator)
  5. [Op.overlap]: [1, 2] // && [1, 2) (PG range overlap (have points in common) operator)
  6. [Op.adjacent]: [1, 2] // -|- [1, 2) (PG range is adjacent to operator)
  7. [Op.strictLeft]: [1, 2] // << [1, 2) (PG range strictly left of operator)
  8. [Op.strictRight]: [1, 2] // >> [1, 2) (PG range strictly right of operator)
  9. [Op.noExtendRight]: [1, 2] // &< [1, 2) (PG range does not extend to the right of operator)
  10. [Op.noExtendLeft]: [1, 2] // &> [1, 2) (PG range does not extend to the left of operator)

Combinations

  1. const Op = Sequelize.Op;
  2. {
  3. rank: {
  4. [Op.or]: {
  5. [Op.lt]: 1000,
  6. [Op.eq]: null
  7. }
  8. }
  9. }
  10. // rank < 1000 OR rank IS NULL
  11. {
  12. createdAt: {
  13. [Op.lt]: new Date(),
  14. [Op.gt]: new Date(new Date() - 24 * 60 * 60 * 1000)
  15. }
  16. }
  17. // createdAt < [timestamp] AND createdAt > [timestamp]
  18. {
  19. [Op.or]: [
  20. {
  21. title: {
  22. [Op.like]: 'Boat%'
  23. }
  24. },
  25. {
  26. description: {
  27. [Op.like]: '%boat%'
  28. }
  29. }
  30. ]
  31. }
  32. // title LIKE 'Boat%' OR description LIKE '%boat%'

Operators Aliases

Sequelize allows setting specific strings as aliases for operators. With v5 this will give you deprecation warning.

  1. const Op = Sequelize.Op;
  2. const operatorsAliases = {
  3. $gt: Op.gt
  4. }
  5. const connection = new Sequelize(db, user, pass, { operatorsAliases })
  6. [Op.gt]: 6 // > 6
  7. $gt: 6 // same as using Op.gt (> 6)

Operators security

By default Sequelize will use Symbol operators. Using Sequelize without any aliases improves security. Not having any string aliases will make it extremely unlikely that operators could be injected but you should always properly validate and sanitize user input.

Some frameworks automatically parse user input into js objects and if you fail to sanitize your input it might be possible to inject an Object with string operators to Sequelize.

For better security it is highly advised to use symbol operators from Sequelize.Op like Op.and / Op.or in your code and not depend on any string based operators like $and / $or at all. You can limit alias your application will need by setting operatorsAliases option, remember to sanitize user input especially when you are directly passing them to Sequelize methods.

  1. const Op = Sequelize.Op;
  2. //use sequelize without any operators aliases
  3. const connection = new Sequelize(db, user, pass, { operatorsAliases: false });
  4. //use sequelize with only alias for $and => Op.and
  5. const connection2 = new Sequelize(db, user, pass, { operatorsAliases: { $and: Op.and } });

Sequelize will warn you if you're using the default aliases and not limiting themif you want to keep using all default aliases (excluding legacy ones) without the warning you can pass the following operatorsAliases option -

  1. const Op = Sequelize.Op;
  2. const operatorsAliases = {
  3. $eq: Op.eq,
  4. $ne: Op.ne,
  5. $gte: Op.gte,
  6. $gt: Op.gt,
  7. $lte: Op.lte,
  8. $lt: Op.lt,
  9. $not: Op.not,
  10. $in: Op.in,
  11. $notIn: Op.notIn,
  12. $is: Op.is,
  13. $like: Op.like,
  14. $notLike: Op.notLike,
  15. $iLike: Op.iLike,
  16. $notILike: Op.notILike,
  17. $regexp: Op.regexp,
  18. $notRegexp: Op.notRegexp,
  19. $iRegexp: Op.iRegexp,
  20. $notIRegexp: Op.notIRegexp,
  21. $between: Op.between,
  22. $notBetween: Op.notBetween,
  23. $overlap: Op.overlap,
  24. $contains: Op.contains,
  25. $contained: Op.contained,
  26. $adjacent: Op.adjacent,
  27. $strictLeft: Op.strictLeft,
  28. $strictRight: Op.strictRight,
  29. $noExtendRight: Op.noExtendRight,
  30. $noExtendLeft: Op.noExtendLeft,
  31. $and: Op.and,
  32. $or: Op.or,
  33. $any: Op.any,
  34. $all: Op.all,
  35. $values: Op.values,
  36. $col: Op.col
  37. };
  38. const connection = new Sequelize(db, user, pass, { operatorsAliases });

JSON

The JSON data type is supported by the PostgreSQL, SQLite, MySQL and MariaDB dialects only.

PostgreSQL

The JSON data type in PostgreSQL stores the value as plain text, as opposed to binary representation. If you simply want to store and retrieve a JSON representation, using JSON will take less disk space and less time to build from its input representation. However, if you want to do any operations on the JSON value, you should prefer the JSONB data type described below.

MSSQL

MSSQL does not have a JSON data type, however it does provide support for JSON stored as strings through certain functions since SQL Server 2016. Using these functions, you will be able to query the JSON stored in the string, but any returned values will need to be parsed seperately.

  1. // ISJSON - to test if a string contains valid JSON
  2. User.findAll({
  3. where: sequelize.where(sequelize.fn('ISJSON', sequelize.col('userDetails')), 1)
  4. })
  5. // JSON_VALUE - extract a scalar value from a JSON string
  6. User.findAll({
  7. attributes: [[ sequelize.fn('JSON_VALUE', sequelize.col('userDetails'), '$.address.Line1'), 'address line 1']]
  8. })
  9. // JSON_VALUE - query a scalar value from a JSON string
  10. User.findAll({
  11. where: sequelize.where(sequelize.fn('JSON_VALUE', sequelize.col('userDetails'), '$.address.Line1'), '14, Foo Street')
  12. })
  13. // JSON_QUERY - extract an object or array
  14. User.findAll({
  15. attributes: [[ sequelize.fn('JSON_QUERY', sequelize.col('userDetails'), '$.address'), 'full address']]
  16. })

JSONB

JSONB can be queried in three different ways.

Nested object

  1. {
  2. meta: {
  3. video: {
  4. url: {
  5. [Op.ne]: null
  6. }
  7. }
  8. }
  9. }

Nested key

  1. {
  2. "meta.audio.length": {
  3. [Op.gt]: 20
  4. }
  5. }

Containment

  1. {
  2. "meta": {
  3. [Op.contains]: {
  4. site: {
  5. url: 'http://google.com'
  6. }
  7. }
  8. }
  9. }

Relations / Associations

  1. // Find all projects with a least one task where task.state === project.state
  2. Project.findAll({
  3. include: [{
  4. model: Task,
  5. where: { state: Sequelize.col('project.state') }
  6. }]
  7. })