Cannot Get Data From Nested SQL Query - mysql

const getCompanyShifts = (req, res) => {
try {
const { company_id } = req.params;
connection.query(
`SELECT * FROM jobs WHERE company_fk=${company_id}`,
(err, rowss) => {
if (!err) {
connection.query(
`SELECT * FROM shift WHERE isBooked=1 AND fk_job = ?`,
[rowss.jobsID],
(err, rows) => {
if (err || rows.length === 0) {
res.status(404).json({
success: false,
message: "Company Shifts Not Found!",
err,
});
} else {
const shifts = [];
rows.forEach((row, i) => {
const shift = {
shiftID: rows[i].shiftID,
shiftStartTime: rows[i].startTime,
shiftEndTime: rows[i].endTime,
shiftDate: rows[i].date,
isBooked: rows[i].isBooked,
fk_job: rows[i].fk_job,
fk_guard: rows[i].fk_guard,
};
shifts.push(shift);
});
res.status(200).json({
success: true,
message: "Successfully Retrieved Company Shifts!",
shifts,
});
}
}
);
} else {
res.status(404).json({
success: false,
message: "Company Jobs Not Found!",
});
}
}
);
} catch (error) {
res.status(500).json({
success: false,
message: error.message,
});
}
};
in the first query of the above code, i am getting all the rows from the jobs table. In the second nested query, i am trying to get all rows from the shift table for each of the jobsID returned from the 1st query. But i don't get any data back. The data exists and it should return data but i don't get any data back. What am i doing wrong here ? Please help!

i assume there is a misunderstanding on how the data gets returned and therefore how the second query would work. According to your statement:
[...] i am getting all the rows from the jobs table. In the second nested
query, i am trying to get all rows from the shift table for each of
the jobsID returned from the 1st query. But i don't get any data back.
You are getting multiple rows back. So the first query works. But getting multiple rows back would result in rowss being an array. Therefore rowss.jobsID which is used as input for the next query isn't a correct use of an array and i expect the value of that expression to be undefined which will then result in the second query not returning anything.
To prove that add console.log(rowss) like so:
[...]
connection.query(
`SELECT * FROM jobs WHERE company_fk=${company_id}`,
(err, rowss) => {
console.log(rowss);
[...]
To solve the issue, i suggest to use sql capabilities and issue a join. By doing so, the Database will join the two tables, then returning only rows that fulfill the where condition. The combined statement should look like:
SELECT * FROM jobs WHERE company_fk=${company_id} LEFT JOIN shift ON shift.fk_job = jobs.jobsID WHERE isBooked=1
Hint: Depending on your DB schemes for ob'sand shift you might need to expand the * and list all table names explicitly, e.g. SELECT jobs.jobsID, jobs.<xyz>, shift.isBooked, shift.fk_job [...] FROM [...]. If you have column with same name in both tables, you might need to resolve the conflict which is caused by the join while combining the columns for returning the results like so: SELECT [...] shift.<xyz> as shift_xyz [...] FROM ...[].
As a plus, you also just need one SQL query instead of two.

Related

How to get only the value of a stringified MySQL query result?

After executing this query:
con.query("SELECT name FROM members WHERE id=1", function(err, rows, fields) {
console.log(rows);
});
this is what I get:
[ RowDataPacket { name: 'John' } ]
I expect only one record and I only want to get John. How do I do that?
Short of writing your own additional function(s) and passing the row object through them your desired result format is not possible based on the design of the mysqljs/mysql package. In a standard SELECT query the result is always an object.
There is a bit of a hack workaround by using the stream function. Below is an example, but you will still end up with more lines of code than you would if you simply accessed the value via rows[0].name in a standard query.
let the_query = con.query('SELECT name FROM members WHERE id = 1;');
the_query
.on('result', function(row) {
console.log('row.name:', row.name);
// expected in log:
// row.name: John
})
.on('end', function() {
// this chained event can be excluded
// here for demo purposes
console.log('all done');
});
JSON.stringify(RowDataPacket[0].name)
This will output:
John

Node Mysql undefined field on multiple queries

I'm using node, express, mysql
I'm doing multiple sql queries
app.get("/surveys/:id/edit", function (req, res) {
var q =
"\
SELECT * FROM inference_db.surveys WHERE surveys.slug=?; \
SELECT * FROM inference_db.imagez; \
SELECT city_id, name, province FROM inference_db.cities WHERE cities.type != 1;"
connection.query(q, [req.params.id], function (error, results, fields) {
if (error) throw error;
console.log(results[0]);
console.log("------------participating cities----------------- ");
console.log(results[0].participating_cities);
res.render("edit.ejs", {
pageTitle: "xdit Survey",
items1: results[0], // survey
items2: results[1], // imagez
items3: results[2] // cities
});
});
});
When I console log results[0], it is working and gives me all the fields.
But when I console log results[0].participating_cities, i get undefined. I need that field because I will pass it as an array. That field is a string stored in mysql table. Can anyone please help. Thanks!
My console log:
topic_id: 1,
featured: 1,
image: 'imee_marcos.jpg',
slug: 'test-html-Mar-06-2019',
status: '1',
participating_cities: '30,40',
participating_groups: '2,3' } ]
------------participating cities-----------------
undefined
results will be an array of query results for each of the queries you ran; but each of those results is an array in itself. So you probably want to check out the value of results[0][0].participating_cities if you want to get that field from the first row of the first result.

Node + Mysql: How to execute more queries based on another query

I'm pretty new to the node world and trying to migrate our php application to node. To be able to return all article data several different queries have to be done depending on the results of the first query. Currently my data object is empty as it's returned before the two queries run. How can I "chain" these queries using a promised based approach.
I found a library https://github.com/lukeb-uk/node-promise-mysql which I think could help but I have no idea how to implement it with my code.
exports.getArticleData = function(req, done) {
pool.getConnection(function(error, connection) {
if (error) throw error;
var data = {
article: {},
listicles: []
};
// Inital query
connection.query(
`SELECT article_id, title, is_listicle_article, FROM com_magazine_articles AS article WHERE article_id = ${req
.params.articleId}`,
function(error, results) {
data.article = results;
}
);
// This query should only be excuted if is_listicle_article = true
if (data.article.is_listicle_article) {
connection.query(
`SELECT * FROM com_magazine_article_listicles WHERE article_id = ${req.params
.articleId}`,
function(error, results) {
data.listicle = results;
}
);
}
// More queries depending on the result of the first one
// ....
// ....
// Callback with the data object
done(data);
connection.release();
});
};
What would be the best approach to execute queries based on other queries results? Any help is really appreciated.
The functionality you are looking for is Promise chaining, it allows you to construct a sequence of promises, each depending on the result of the previous value. Applying this to your code, you would get something like this:
exports.getArticleData = function(req, done) {
pool.getConnection(function(error, connection) {
if (error) throw error;
// Inital query
return connection.query(
`SELECT article_id, title, is_listicle_article, FROM com_magazine_articles AS article WHERE article_id = ${req
.params.articleId}`
).then((rows) => {
return Promise.all(rows.map((article) => {
if (article.is_listicle_article) {
return connection.query(
`SELECT * FROM com_magazine_article_listicles WHERE article_id = ${req.params
.articleId}`
);
} else {
return Promise.resolve(null);
}
}));
}).then((res) => {
connection.release();
done(res.filter(function(i){ return i != null; }));
})
// This query should only be excuted if is_listicle_article = true
// More queries depending on the result of the first one
// ....
// ....
// Callback with the data object
connection.release();
});
};
Obviously since I don't have all of your code, I couldn't verify this example, but this should be roughly the functionality you are looking for. That said, I think there were a couple of mistakes you should watch out for in your example code:
connection.query() returns a promise (aka doesn't need a callback function). Use this functionality to your advantage- it will make your code prettier.
connection.query() returns an array of rows, not a single value. You seemed to ignore this in your example code.
Try not to save things into a variable when using promises, it isn't necessary. To remedy this, read more into the Promise API (Promise.resolve(), Promise.reject(), Promise.any(), Promise.catch(), Promise.all()) etc.
It seems like these SQL queries could easily be combined into a single query. This will be way more efficient that performing two operations. Not sure if this is the case with the remaining queries you wish to use, but definitely something to look out for.

Getting MySQL fields in NodeJS

I know this is possibly a duplicate but I cannot seem to get it to work.
connection.query('SELECT * FROM software', function(err, rows) {
if (err) {
next(new Error(err));
} else {
data.db = rows[1].language;
data.no = rows.length;
console.log(data.db);
}
});
I am trying to reference a specific field in a row retrieved. I have a row called 'Language' in my table so have researched around and found that I can reference the name of the field. When I do this, it throws back undefined in the console. It returns the same when I reference any other field (i.e. id)

Find row by UUID stored as binary in SequelizeJS

I have a Sequelize object called Org which represents a row in the organisations table stored in MySQL. This table has a UUID primary key(id) stored as a 16 byte varbinary. If I have the UUID of an object (bfaf1440-3086-11e3-b965-22000af9141e) as a string in my JavaScript code, what is the right way to pass it as a parameter in the where clause in Sequelize?
Following are the options I've tried
Model: (for an existing MySQL table)
var uuid = require('node-uuid');
module.exports = function(sequelize, Sequelize) {
return sequelize.define('Org', {
id: {
type: Sequelize.BLOB, //changing this to Sequelize.UUID does not make any difference
primaryKey: true,
get: function() {
if (this.getDataValue('id')) {
return uuid.unparse(this.getDataValue('id'));
}
}
},
name: Sequelize.STRING,
}, {
tableName: 'organisation',
timestamps: false,
}
});
};
Option 1: Pass UUID as byte buffer using node-uuid
Org.find({
where: {
id: uuid.parse(orgId)
}
}).then(function(org) {
success(org);
}).catch(function(err) {
next(err);
});
Executing (default): SELECT `id`, `name` FROM `Organisation` AS `Org`
WHERE `Org`.`id` IN (191,175,20,64,48,134,17,227,185,101,34,0,10,249,20,30);
Sequelize treats the byte buffer as multiple values and so I get multiple matches and the top most record (not the one that has the right UUID) gets returned.
Option 2: Write a raw SQL query and pass the UUID as a HEX value
sequelize.query('SELECT * from organisation where id = x:id', Org, {plain: true}, {
id: orgId.replace(/-/g, '')
}).then(function(org) {
success(org);
}).catch(function(err) {
next(err);
});
Executing (default): SELECT * from organisation
where id = x'bfaf1440308611e3b96522000af9141e'
I get the correct record, but this approach is not really useful as I have more complex relationships in the DB and writing too many queries by hand beats the purpose of the ORM.
I'm using Sequelize 2.0.0-rc3.
Solved it by supplying a fixed size empty Buffer object to uuid.parse().
Got it working initially using ByteBuffer, but then realised that the same can be achieved using uuid.parse()
Org.find({
where: {
id: uuid.parse(orgId, new Buffer(16))
}
}).then(function(org) {
console.log('Something happened');
console.log(org);
}).catch(function(err) {
console.log(err);
});
Executing (default): SELECT `id`, `name` FROM `Organisation` AS `Org`
WHERE `Org`.`id`=X'bfaf1440308611e3b96522000af9141e';
If the accepted answer didn't work for you, here's what worked for me.
Note: My objective is to find an instance of an event based on a column which is not the primary key.
// guard clause
if (!uuid.validate(uuid_code))
return
const _event = await event.findOne({ where: { uuid_secret: uuid_code } })
// yet another guard clause
if (_event === null)
return
// your code here