How do you include a concat call with other criteria in sequelize? - mysql

I have a front end with a singular input to search names however my database separated them into 2 fields. What I want to do is run a concat and like statement alone the lines of:
SELECT * FROM users WHERE (CONCAT(first_name, ' ', last_name)) LIKE '%John Do%' AND permission_id = 1 AND user_status_id = 1;
now I've gotten to this:
let name = req.params.name;
let userId = req.user;
debugger;
db.user.findAll({
where: {
attributes: [db.sequelize.fn('concat', db.Sequelize.col('first_name'), ' ', db.Sequelize.col('last_name'), 'full_name'), {
like: `%${name}%`
}],
},
include : [
db.client
]
})
but can't think where to include the like or the concat

Related

Nodejs | add table columns and values conditionally in sql query statment

I want to simplify my mysql queries. Here is my current query where I need to include columns conditionally and so there values:
const hasPassword = false;
const myEmail = xyz#yopmail.com;
const myPassword = 123456;
query("SELECT id, name, email, status, (hasPassword ? 'password ,' : '') FROM users WHERE email=${myEmail} (hasPassword ? 'AND password=${myPassword}' : '')"
How to write simplified query similar to the below format:
query("SELECT id, name, email FROM users email=? AND password=?",[email, password]);

Loopback 3 pure SQL query with params not working with question marks (with Solution)

My query was like:
let query = `SELECT id, name FROM students WHERE school_code = "${schoolCode}" AND name REGEXP "${text}" `;
And with params:
let params = [ schoolCode, text ];
let query = `SELECT id, name FROM students WHERE school_code = "?" AND name REGEXP "?" `
Model.dataSource.connector.query(query, params, (err, res) => {} );
And it wouldn't work
(Solution below)
I thought maybe it was the REGEXP but
The Solution Was:
to remove quotes around the question marks.
e.g., this worked:
let params = [ schoolCode, text ];
let query = `SELECT id, name FROM students WHERE school_code = ? AND name REGEXP ? `
Model.dataSource.connector.query(query, params, (err, res) => {} );

How to create an sql statement with optional parameters

I have a lessons table that contains the following fields:
id title type language level
The user through the interface can select witch lesson he wants to open.
He will start selecting the language, then the type and finally the level.
During this process I want to query the database using a single sql statement, but of course the first query will have only the language field. I came up with this syntax but it does not work:
function queryLessonList (language, type, level){
const values = [language, type, level];
const sql = "SELECT * FROM lessons WHERE (language=?) AND (? is null OR type=?) AND (? is null OR level=?)";
return query(sql, values);
}
How can I make it work?
To reduce the complexity of checking variables and building out the query, instead you can pass the function an object to match, what you want and the columns you want returning etc (as * is not ideal).
So something like:
function queryLessonList (where = {}, columns = ['*']) {
let keys = Object.keys(where)
let values = Object.values(where)
columns = !columns.length || columns[0] === '*' ?
'*': columns.map(e => '`'+e+'`').join(',')
let sql = `
SELECT ${columns}
FROM lessons
${keys.length ? 'WHERE \`'+keys.join('` = ? AND `')+'\` = ?' : ''}
`
return query(sql, values)
}
/*
SELECT *
FROM lessons
WHERE `language` = ? AND `type` = ?
*/
queryLessonList({
language: 'en',
type: 'foo'
}, [])
/*
SELECT `id`
FROM lessons
*/
queryLessonList({}, ['id'])
/*
SELECT *
FROM lessons
*/
queryLessonList()

rewrite left outer join for sub queries in bookshelf.js

Note : I have not shared database schema as I am mainly looking for a help only w.r.t. last step which is 'left outer join' on 2 sub-queries.
select *
from
(select id
from Action
where id = 3) AS act1
left Outer Join
(select Action.name,
completed_At as completedAt,
deadline, notes,
ActionAssignedTo.action_Id as actionId,
from Action
inner join Employee
on Action.created_By_Id = Employee.id
and Employee.vendor_Id = 2
inner join ActionAssignedTo
on Action.id = ActionAssignedTo.action_Id
and ActionAssignedTo.action_Id = 3
where Action.created_By_Id = 7
group by Action.id
limit 2) AS act2
on act1.id = act2.actionId
I need to write this above query using Bookshelf
let options = {columns: [ 'Action.name', 'completed_At as completedAt',
'deadline', 'notes',
'ActionAssignedTo.action_Id as actionId',
]};
let action2 = new Action();
action2.query().innerJoin('Employee', function () {
this.on('Action.created_By_Id', 'Employee.id')
.andOn('Employee.vendor_Id', bookshelf.knex.raw(1));
});
action2.query().innerJoin('ActionAssignedTo', function () {
this.on('Action.id', 'ActionAssignedTo.action_Id')
.andOn('ActionAssignedTo.action_Id', bookshelf.knex.raw(5));
});
action2.query().where(function() {
this.where('Action.created_By_Id', empId)
});
action2.query().groupBy('Action.id');
action2.query().limit(2);
action2.query().columns(options.columns);
let action1;
action1 = Action.where('id', actionId);
action1.query().columns('id');
return bookshelf.knex.raw('select * from '
+ '(' + action1.query().toString() + ') AS act1'
+ ' left Outer Join '
+ '(' + action2.query().toString() + ') AS act2'
+ ' on act1.id = act2.actionId');
I am not keen on using bookshelf.knex.raw for using the left Outer Join as the output given by knex.raw and bookshelf differ.
Is there a way I can do the 'left Outer Join' directly using bookshelf library.
I looked into the code but it seems leftOuterJoin only takes table name as the first parameter and what I need is a query.
I think your main problem is that you're using Bookshelf like you would be using knex. Bookshelf is meant to be used with models you would define and then query on them.
Here is an example of what you should have as model
// Adding registry to avoid circular references
// Adding camelcase to get your columns names converted to camelCase
bookshelf.plugin(['bookshelf-camelcase', 'registry']);
// Reference: https://github.com/brianc/node-pg-types
// These two lines convert all bigint values coming from Postgres from JS string to JS integer.
// Removing these lines will mess up with Bookshelf count() methods and bigserial values
pg.types.setTypeParser(20, 'text', parseInt);
const Action = db.bookshelf.Model.extend({
tableName: 'Action',
createdBy: function createdBy() {
return this.belongsTo(Employee, 'id', 'created_By_Id');
},
assignedTo: function assignedTo() {
return this.hasMany(ActionAssignedTo, 'action_id');
},
});
const Employee = db.bookshelf.Model.extend({
tableName: 'Employee',
createdActions: function createdActions() {
return this.hasMany(Action, 'created_By_Id');
},
});
const ActionAssignedTo = db.bookshelf.Model.extend({
tableName: 'ActionAssignedTo',
action: function action() {
return this.belongsTo(Action, 'id', 'action_Id');
},
employee: function employee() {
return this.belongsTo(Employee, 'id', 'employee_Id');
},
});
module.exports = {
Action: db.bookshelf.model('Action', Action),
Employee: db.bookshelf.model('Employee', Employee),
ActionAssignedTo: db.bookshelf.model('ActionAssignedTo', ActionAssignedTo),
db,
};
You would then be able to fetch your results with a query like this
const Model = require('model.js');
Model.Action
.where({ id: 3 })
.fetchAll({ withRelated: ['createdBy', 'assignedTo', 'assignedTo.employee'] })
.then(data => {
// Do what you have to do
});
What your want to achieve is not possible with only one query in Bookshelf. You probably need to do a first query using knex to get a list of Action ids and then give them to Bookshelf.js
db.bookshelf.knex.raw(`
select ActionAssignedTo.action_Id as actionId,
from Action
inner join Employee
on Action.created_By_Id = Employee.id
and Employee.vendor_Id = ?
inner join ActionAssignedTo
on Action.id = ActionAssignedTo.action_Id
and ActionAssignedTo.action_Id = ?
where Action.created_By_Id = ?
group by Action.id
limit ?`,
[2, 3, 7, 2]
)
.then(result => {
const rows = result.rows;
// Do what you have to do
})
And then use the recovered Ids to get your Bookshelf query like this
Model.Action
.query(qb => {
qb.whereIn('id', rows);
})
.fetchAll({
withRelated: [{
'createdBy': qb => {
qb.columns(['id', 'firstname', 'lastname']);
},
'assignedTo': qb => {
qb.columns(['action_Id', 'employee_Id']);
},
'assignedTo.employee': qb => {
qb.columns(['id', 'firstname', 'lastname']);
},
}],
columns: ['id', 'name', 'completed_At', 'deadline', 'notes']
})
.fetchAll(data => {
// Do what you have to do
});
Note that the columns used for joins MUST BE in the columns list for each table. If you omit the columns, all the columns will be selected.
By default, Bookshelf will retrieve all columns and all root objects. The default is kind of LEFT OUTER JOIN.

mysql search child & parent table fields with sequelize in nodejs

In my Node application we have used Sequelize to connect with mysql
Have two table User & UserOption
User table have following fields
user_id(pk)
user_email
UserOption table have following fields
option_id(pk)
user_id(fk)
first_name
I need to list all user by search text in user_email & first_name
Is there any option to search both parent & child table fields in Sequelize?
UPDATE
User table
user_id user_email
1 text#text.com
2 anything#anything.com
3 jhon#smthng.com
UserOption table
option_id user_id first_name
1 1 jhon
2 2 smith
3 3 david
If I search for "jhon", the result will be both user with id 1 and 2
You need to include model UserOption in lookup on model User. This generates a JOIN clause with condition UserOption.user_id = User.user_id, as well as adds specified WHERE clause to perform text lookup on user_email and first_name columns of both tables
User.findAll({
where: {
user_email: { $like: '%text%' }
},
include: [
{
model: UserOption,
where: {
first_name: { $like: '%text%' }
},
attributes: []
}
]
}).then((users) => {
// result
});
EDIT
Basing on your updated question, I think that you can try using sequelize.literal method, but, according to the documentation:
Creates a object representing a literal, i.e. something that will not be escaped.
So it is necessary to escape desired values by yourself
let escValue = sequelize.escape(lookupText);
User.findAll({
where: {
$or: [
{ email: { $like: '%' + lookupText + '%' },
{ id: { $in: sequelize.literal(`(SELECT uo.user_id FROM user_options uo WHERE uo.first_name LIKE CONCAT('%', ${escValue}, '%'))`) }
]
}
}).then((users) => {
// result...
});
It would generate a query which selects users from users table where email LIKE '%text%' or where users.id is in specified query result.
I am very curious if this satisfies your needs, waiting for feedback.