I'm trying to do this, which is exactly as it is in the documentation:
get_ids_query = 'SELECT ?? from ?? WHERE stat = 1 LIMIT 10'
then I call the function with two values placed inside variables:
var name = Table_Names.Tables_PR[t].name
var PK = Table_Names.Tables_PR[t].PK
ids = await this.getIds(PK, name)
This is the function:
async getIds(conf1, conf2) {
return await this.mydb.query(this.get_ids_query, conf1, conf2)
}
and these are the logs:
console.log(PK)
console.log(name)
console.log(mysql.format(this.get_ids_query, conf1, conf2))
output: idusers
users
SELECT `idusers` from ?? WHERE stat = 1 LIMIT 10
I've also tried:
var name = [Table_Names.Tables_PR[t].name]
var PK = [Table_Names.Tables_PR[t].PK]
which logs like this and it still returns the same query:
[ 'idusers' ]
[ 'users' ]
query format: SELECT `idusers` from ?? WHERE stat = 1 LIMIT 10
What am I doing wrong here? why is it reading the first placeholder but won't read the second one?
I am trying to run a simple query with date filter in node.js, even though running the same query from workbench I am getting the data but while running from Node, no rows are returned.
const fetchHistoricalDataQuery = 'SELECT timestamp, \
meter_id AS meterId, \
txn_info_1 AS meterReading, \
txn_info_2 AS txnInfo2, \
txn_info_3 AS txnInfo3, \
txn_info_4 AS txnInfo4, \
txn_info_5 AS txnInfo5, \
date date \
FROM si_agent.historical_data \
WHERE date = ?';
jp_db.fetchHistoricalData = (date) => {
return new Promise((resolve, reject) => {
pool.query(fetchHistoricalDataQuery, [date], (err, results) => {
if (err) {
return reject(err);
} else {
return resolve(results);
}
});
});
};
This is returning no rows when I am passing the input as: "2020-03-21 00:00:00"
whereas running the same query in mysql workbench is giving me the expected response.
SELECT timestamp,
meter_id AS meterId,
txn_info_1 AS meterReading,
txn_info_2 AS txnInfo2,
txn_info_3 AS txnInfo3,
txn_info_4 AS txnInfo4,
txn_info_5 AS txnInfo5,
date date
FROM si_agent.historical_data
WHERE date = "2020-03-21 00:00:00"
Any Idea on why this could be happening?
EDIT:
I tried sending the whole Date object - did not work. new date("2020-03-21 00:00:00")
I am trying to write mysql subquery sql in knex but the results of query are undesired.
This is my MySQL query:
select *
from istifta
where istifta_id not in (
select istifta_id
from status
where status = 'divided'
)
This is my query converted to Knex:
subquery = await ctx.knex
.select('istifta_id')
.from('status')
.where('status', 'divided')
result = await ctx.knex
.select()
.from('istifta')
.where('istifta_id', 'not in', subquery)
MySQL query is returning two rows all of which doesn't have status = 'divided'
While Knex is returning three rows with a row having status = 'divided'
You can use .whereNotIn together with the function() definition option to nest your subquery. Your subquery is inside of the function() as:
select('istifta_id').from('status').where('status', 'divided')
and the .on functions just make debugging a bit easier.
result = await ctx.knex.from('istifta')
.whereNotIn( 'istifta_id', function() {
this.select('istifta_id').from('status').where('status', 'divided')
})
.on('query', function(data) {
console.log("TEST001 data:", data); })
.on('query-error', function(ex, obj) {
console.error("TEST002 KNEX query-error ex:", ex, "obj:", obj);
})
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.
I am building a website using Node and the node-mysql package.
app.get('/api/tags', function(req, res) {
var term = req.query.term;
var query =
'SELECT \
t.tagName \
FROM tags t \
JOIN screencastTags st \
ON st.tagName = t.tagName \
JOIN screencasts s \
ON s.screencastId = st.screencastId \
WHERE s.status = \'approved\' AND t.tagName LIKE \'%' + term + '%\' \
GROUP BY t.tagName \
LIMIT 5';
connection.queryAsync(query).spread(function(tags) {
tags = tags.map(function(tag) { return tag.tagName });
res.send(tags);
})
})
Here I use a value from the query string - term - to return a list of tags.
My question is: How do I prevent against SQL injection when I am using the LIKE operator?
I tried
var query =
'SELECT \
t.tagName \
FROM tags t \
JOIN screencastTags st \
ON st.tagName = t.tagName \
JOIN screencasts s \
ON s.screencastId = st.screencastId \
WHERE s.status = \'approved\' AND t.tagName LIKE \'%' + conneciton.escape(term) + '%\' \
GROUP BY t.tagName \
LIMIT 5';
But that produces invalid SQL.
Try to never build an sql request by concatenation. It indeed always increases the risk of the SQL injection footprint.
A placeholder should work even with the LIKE condition.
var sql = '... LIKE ? GROUP BY ...';
connection.query(sql, ['%' + term + '%'], function(err, res) {})
A prepared statement would even be better for security concerns. you should read https://github.com/felixge/node-mysql/#escaping-query-values