0
votes

I'm trying to do a search on my models, I want to get all users where either the email, firstName, or lastName are like the search string, or where the UsersSecondaryEmails table (related model) includes an email like that string.

Because the parts of the OR statement are in different tables, this is getting a little tricky, and I can only find other StackOverflow answers to help me.

Here is my query (simplified):

const companiesUsersParams = {
  where: {
    companyId: req.params.companyId,
    roleId: role.id
  },
  include: [{
    model: models.Users,
    attributes: ['id', 'firstName', 'lastName', 'email'],
    where: req.query.s ? {
      [Op.or]: [{
        firstName: {
          [Op.like]: `%${req.query.s}%`
        }
      }, {
        lastName: {
          [Op.like]: `%${req.query.s}%`
        }
      }, {
        email: {
          [Op.like]: `%${req.query.s}%`
        }
      }, {
        '$usersSecondaryEmails.email$': {
          [Op.like]: `%${req.query.s}%`
        }
      }]
    } : null,
    include: [{
      model: models.UsersSecondaryEmails,
      attributes: ['id', 'email'],
      as: 'usersSecondaryEmails'
    }]
  }]
}

When req.query.s is not defined, the query runs as expected (No OR statement), so I know it is not an issue with my associations.

When I run this query WITH req.query.s defined, I get

Unknown column 'usersSecondaryEmails.email' in 'on clause'

And here is the SQL being generated (formatted as best as possible):

SELECT `companiesUsers`.`id`,
       `companiesUsers`.`company_id` AS `companyId`, 
       `companiesUsers`.`user_id` AS `userId`,
       `companiesUsers`.`role_id` AS `roleId`,
       `companiesUsers`.`created_at` AS `createdAt`, 
       `companiesUsers`.`updated_at` AS`updatedAt`,
       `user`.`id` AS `user.id`,
       `user`.`first_name` AS `user.firstName`,
       `user`.`last_name` AS `user.lastName`,
       `user`.`email` AS `user.email`,
       `user->usersSecondaryEmails`.`id` AS `user.usersSecondaryEmails.id`,
       `user->usersSecondaryEmails`.`email` AS
       `user.usersSecondaryEmails.email` 
 FROM `CompaniesUsers` AS `companiesUsers`
 INNER JOIN `Users` AS `user`
       ON `companiesUsers`.`user_id` = `user`.`id` AND 
       (`user`.`first_name` LIKE '%bob%' OR
       `user`.`last_name` LIKE '%bob%' OR
       `user`.`email` LIKE '%bob%' OR
       `usersSecondaryEmails`.`email` LIKE '%bob%')
 LEFT OUTER JOIN `UsersSecondaryEmails` AS `user->usersSecondaryEmails`
       ON `user`.`id` = `user->usersSecondaryEmails`.`user_id`
 WHERE `companiesUsers`.`company_id` = '1'
       AND `companiesUsers`.`role_id` = 20;

Any any advice or links to documentation on multi-table OR statements in Sequelize would be great (I couldn't find anything this advanced in the documentation).

1

1 Answers

1
votes

I am not sure how to modify Sequelize code for companiesUsersParams, but your final query should look like below to get desired output. This may help you to rewrite Sequelize code.

  1. Left join on users instead of inner join.
  2. You should move last OR option usersSecondaryEmails.email LIKE '%bob%' to UsersSecondaryEmails join condition
  3. In the where clause, check for the condition (atleast one row should exists in either user table or usersSecondaryEmails for the userid)

    SELECT companiesUsers.id, companiesUsers.company_id AS companyId, companiesUsers.user_id AS userId, companiesUsers.role_id AS roleId, companiesUsers.created_at AS createdAt, companiesUsers.updated_at ASupdatedAt, user.id AS user.id, user.first_name AS user.firstName, user.last_name AS user.lastName, user.email AS user.email, user->usersSecondaryEmails.id AS user.usersSecondaryEmails.id, user->usersSecondaryEmails.email AS user.usersSecondaryEmails.email FROM CompaniesUsers AS companiesUsers LEFT OUTER JOIN Users AS user ---- #1 ON companiesUsers.user_id = user.id AND (user.first_name LIKE '%bob%' OR user.last_name LIKE '%bob%' OR user.email LIKE '%bob%' OR) LEFT OUTER JOIN UsersSecondaryEmails AS user->usersSecondaryEmails ON companiesUsers.user_id = user->usersSecondaryEmails.user_id AND user->usersSecondaryEmails.email LIKE '%bob%' ---- #2 WHERE companiesUsers.company_id = '1' AND companiesUsers.role_id = 20 AND (user.email is Not null OR user->usersSecondaryEmails.user_id is Not Null); ---- #3