Unable to get insertId of the last INSERT in MySQL with NodeJS - mysql

I'm using MySQL with NodeJS with asyncs and awaits. I'm trying to get the last insertid from my inserted row but keep getting errors.
Here's the async function;
function makeDb( config ) {
const connection = mysql.createConnection( config ); return {
query( sql, args ) {
return util.promisify( connection.query )
.call( connection, sql, args );
},
close() {
return util.promisify( connection.end ).call( connection );
}
};
}
And here's the code which is failing on the queries;
try {
if(tag1){
row_b = await db.query( "SELECT tagid FROM tags WHERE tagname = ?", [tag1]);
const onetagid1 = row_b[0].tagid;
console.log('onetagid1 = ' + onetagid1);
if (row_b > 0){
row_c = await db.query("
INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?" [onetagid1, audioid, onetagid1]
);
} else {
row_d = await db.query( 'INSERT IGNORE INTO tags (tagname) VALUES (?)', [tag1]);
var twotagid1 = row_d.insertId;
console.log('twotagid1 2nd = ' + twotagid1);
row_e = await db.query(
"INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?" [twotagid1, audioid, twotagid1]
);
}
res.json('json success!');
}
}
And here's the error;
onetagid1 = 30
twotagid1 2nd = 0
ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'I' at line 1
The error is twotagid1 2nd = 0 which should not be zero.

I'm not sure why this works when the other didn't. But I'll post it here hoping someone will be able to spot it;
try {
if(tag1){
row_c = await db.query( "SELECT tagid FROM tags WHERE tagname = ?", [tag1]);
if (row_c.length > 0){
console.log('tag exists in database ');
const tagid1 = row_c[0].tagid;
console.log('tagid1 = ' + tagid1);
row_f = await db.query(
"INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?", [tagid1, audioid, tagid1 ]);
} else {
console.log('tag does not exist in database ');
row_d = await db.query( 'INSERT IGNORE INTO tags (tagname) VALUES (?)', [tag1]);
const tagInsertId = row_d.insertId;
console.log('tagInsertId = ' + tagInsertId);
row_e = db.query(
'INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?', [tagInsertId, audioid, tagInsertId ]);
}
}
console.log('success!');
res.json(tag1);
}

Related

How do I post data from form to a particular row?

My nodejs code...
app.post('/src/grades-form', function(req, res){
var daa = req.body.daa;
var os = req.body.os;
var dldm = req.body.dldm;
var ptrp = req.body.ptrp;
var bhr = req.body.bhr;
var prn = req.query.prn;
var sql = "INSERT INTO grades (daa, os, dldm, ptrp, bhr) VALUES ('"+daa+"','"+ os+"','"+ dldm+"','"+ ptrp+"','"+ bhr+"') WHERE prn = ?";
connection.query(sql, [prn], function(error, results){
if(error) throw error;
res.send(`Data stored successfully !!<br>Return to dashboard.`);
});
});
Error I'm getting...
Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near 'WHERE prn = '1'' at line 1
How do I overcome it?
I will provide more info if this isn't sufficient... Thank you
What you could do is perform a SELECT to check if the row is present in the database, if so perform an update, otherwise insert a new row:
app.post('/src/grades-form', function (req, res) {
const { daa, os, dldm, ptrp, bhr } = req.body;
var prn = req.query.prn;
const sqlSelect = 'SELECT * FROM grades WHERE prn = ?';
connection.query(sqlSelect, [prn], (err, result) => {
if (err) throw err;
if (result.length === 0) {
// Not found, insert new value
var sqlInsert =
'INSERT INTO grades (daa, os, dldm, ptrp, bhr) VALUES (?, ?, ?, ?, ?)';
connection.query(
sqlInsert,
[daa, os, dldm, ptrp, bhr],
function (error, results) {
if (error) throw error;
res.send(
`Data inserted successfully !!<br>Return to dashboard.`
);
}
);
} else {
// Value is present, update existing one
var sqlUpdate =
'UPDATE grades SET daa = ?, os = ?, dldm = ?, ptrp = ?, bhr = ? WHERE prn = ?';
connection.query(
sqlUpdate,
[daa, os, dldm, ptrp, bhr, prn],
function (error, results) {
if (error) throw error;
res.send(
`Data updated successfully !!<br>Return to dashboard.`
);
}
);
}
});
});
The INSERT INTO statement cannot have a WHERE clause.
If you're trying to update an existing row, use:
UPDATE grades SET daa=value, os=value, etc=value WHERE prn = 1

MySQL ON DUPLICATE KEY UPDATE in NodeJS

I'm using NodeJS with MySQL and async/await statements. I've got a UNIQUE column in a MySQL table named audioid.
I need to check if an audioid exists. If so I need to update a row. If not I need to insert a row. I'm using MySQL's So here's the query;
try {
if(tag1){
row_b = await db.query( "SELECT tagid FROM tags WHERE tagname = ?", [tag1]);
if (row_b > 0){
const tagid1 = row_b[0].tagid;
console.log('tagid first = ' + tagid1);
row_c = await db.query(
"INSERT INTO entitytag (tagid1) VALUES (?) WHERE audioid = ?
ON DUPLICATE KEY UPDATE tagid1 = ?", [tagid1, audioid, tagid1]
);
}
else {
row_d = await db.query( 'INSERT IGNORE INTO tags (tagname) VALUES (?)', [tag1]);
const tagid1 = row_d.insertId;
console.log('tagid 2nd = ' + tagid1);
row_e = await db.query(
"INSERT INTO entitytag (tagid1) VALUES (?) WHERE audioid = ?
ON DUPLICATE KEY UPDATE tagid1 = ?", [tagid1, audioid, tagid1]
);
}
console.log('success!');
res.json('success!');
}
}
But there's the error in the console;
[ RowDataPacket { tagid: 11 } ]
tagid 2nd = 0
ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE audioid = 26 ON DUPLICATE KEY UPDATE tagid1 = 0' at line 1
INSERT INTO entitytag (tagid1) VALUES (?) WHERE audioid = ?
ON DUPLICATE KEY UPDATE tagid1 = ?
is wrong on a SQL basis since insert creates a new row, so there are no WHERE conditions applicable. If you want to specify that the duplicate check should happen on audioid then you should create an index on the table with UNIQUE attribute on that field.
The correct query (from an syntax standpoint only) is
INSERT INTO entitytag (tagid1) VALUES (?)
ON DUPLICATE KEY UPDATE tagid1 = ?
Without having sample data,expected results and table structures it is a matter of guessing but a working (functionally) query could be:
INSERT INTO entitytag (tagid1, audioid) VALUES (?,?)
ON DUPLICATE KEY UPDATE tagid1 = ?

Node JS for loop and database query

I'm running a for loop on a function, and the database is updated on each loop. It then calls the database again using the for loop to update values on the database. However it seems to appear like i'm getting cached results. Is there any reason for this error?
I can post my code, but it's kind of tedious.
It's a simple for loop on a module function that calls a database request, then updates that database.
module.exports.newElectronicHyperCredit = function(request){
gt = request.body.custom + "-" + Date.now()
db.query(
"SELECT * FROM Tenderizer.Stats ORDER BY ID DESC LIMIT 1",
[
],
function(error, stats){
bsr = stats[0]['BuySellRate'];
dv = stats[0]['DollarValue'];
credits = stats[0]['Credits'];
for(i = 0; i < request.body.quantity; i++){
bsr = dv / credits;
dv = Number(dv) + 10;
credits = Number(credits) + (7 / BSR);
denomination = 7 / bsr;
db.query(
"INSERT INTO Tenderizer.Stats SET ?",
{
BuySellRate: bsr,
DollarValue: dv,
Credits: credits
},
function(error, stats){
}
)
db.query(
"SELECT * FROM Tenderizer.Withdrawals ORDER BY case when Withdrawals.Owner = 'Rah1337' then 1 else 2 end, Withdrawals.ID DESC",
[
],
function(error, withdrawals){
withdrawn = 0;
for(x in withdrawals){
if(denomination != 0){
if(withdrawals[x]['Denomination'] > denomination){
withdrawn = withdrawn + denomination;
db.query(
"UPDATE Tenderizer.Withdrawals SET Denomination = Denomination - ? WHERE ID = ?",
[
denomination,
withdrawals[x]['ID']
],
function(error, points){
}
);
db.query(
"INSERT INTO Tenderizer.Points SET ?",
{
GenerationTag: withdrawals[x]['GenerationTag'],
Owner: request.body.custom,
Denomination: denomination,
BoughtPoint: bsr,
Since: Date.now()
},
function(error, points){
}
);
db.query(
"INSERT INTO Tenderizer.Payouts SET ?",
{
GenerationTag: withdrawals[x]['GenerationTag'],
Owner: withdrawals[x]['Owner'],
DollarValue: bsr * withdrawals[x]['Denomination'],
Denomination: denomination,
Processed: 0,
Since: Date.now()
},
function(error, payouts){
}
);
denomination = 0;
}else{
withdrawn = withdrawn + denomination;
db.query(
"DELETE FROM Tenderizer.Withdrawals WHERE ID = ?",
[
withdrawals[x]['ID']
],
function(error, withdrawals){
}
);
db.query(
"INSERT INTO Tenderizer.Points SET ?",
{
GenerationTag: withdrawals[x]['GenerationTag'],
Owner: request.body.custom,
Denomination: withdrawals[x]['Denomination'],
BoughtPoint: bsr,
Since: Date.now()
},
function(error, points){
}
);
db.query(
"INSERT INTO Tenderizer.Payouts SET ?",
{
GenerationTag: withdrawals[x]['GenerationTag'],
Owner: withdrawals[x]['Owner'],
DollarValue: bsr * withdrawals[x]['Denomination'],
Denomination: withdrawals[x]['Denomination'],
Processed: 0,
Since: Date.now()
},
function(error, payouts){
}
);
denomination = denomination - withdrawals[x]['Denomination'];
}
}
}
if(denomination > 0){
db.query(
"INSERT INTO Tenderizer.Pool SET ?",
{
GenerationTag: gt,
Username: request.body.custom,
DollarValue: 10 - (withdrawn * bsr),
Withdrawn: 0,
Since: Date.now()
},
function(error, pool){
}
);
db.query(
"INSERT INTO Tenderizer.Points SET ?",
{
GenerationTag: gt,
Owner: request.body.custom,
Denomination: denomination,
BoughtPoint: bsr,
Since: Date.now()
},
function(error, points){
}
);
}
db.query(
"UPDATE Tenderizer.EHC_Count SET Credits = Credits + ? WHERE Username = ?",
[
7 / bsr
],
function(error, ehc_count){
}
);
}
);
}
}
);
};
It's not inserting the records one by one, it's inserting it all at once or it's using cached results. Because the rows that i'm recieving in my database are
duplicate rows rather than incrementing rows. In the points table in the denomination column and the bought point.
You're using lots of callbacks, but you're not actually doing anything to wait until those callbacks are called. This is difficult to resolve using callbacks, but could be done much more easily if you use a library that supports Promises.
For example, this is what the code would look like if you properly await each query using #databases/mysql
const createConnectionPool = require('#databases/mysql');
const {sql} = require('#databases/mysql');
const db = createConnectionPool();
module.exports.newElectronicHyperCredit = async function(request){
let gt = request.body.custom + "-" + Date.now()
const stats = await db.query(
sql`SELECT * FROM Tenderizer.Stats ORDER BY ID DESC LIMIT 1`,
);
let bsr = stats[0]['BuySellRate'];
let dv = stats[0]['DollarValue'];
let credits = stats[0]['Credits'];
for(let i = 0; i < request.body.quantity; i++){
bsr = dv / credits;
dv = Number(dv) + 10;
credits = Number(credits) + (7 / BSR);
denomination = 7 / bsr;
await db.query(sql`
INSERT INTO Tenderizer.Stats (BuySellRate, DollarValue, Credits)
VALUES (${bsr}, ${dv}, ${credits}
`)
const withdrawals = await db.query(sql`
SELECT * FROM Tenderizer.Withdrawals
ORDER BY case when Withdrawals.Owner = 'Rah1337' then 1 else 2 end, Withdrawals.ID DESC
`)
withdrawn = 0;
for(x in withdrawals){
if(denomination != 0){
if(withdrawals[x]['Denomination'] > denomination){
withdrawn = withdrawn + denomination;
await db.query(sql`
UPDATE Tenderizer.Withdrawals
SET Denomination = Denomination - ${denomination}
WHERE ID = ${withdrawals[x]['ID']}
`);
await db.query(sql`
INSERT INTO Tenderizer.Points (GenerationTag, Owner, Denomination, BoughtPoint, Since)
VALUES (
${withdrawals[x]['GenerationTag']},
${request.body.custom},
${denomination},
${bsr},
${Date.now()}
)
`);
await db.query(sql`
INSERT INTO Tenderizer.Payouts (GenerationTag, Owner, DollarValue, Denomination, Processed, Since)
VALUES (
${withdrawals[x]['GenerationTag']},
${withdrawals[x]['Owner']},
${bsr * withdrawals[x]['Denomination']},
${denomination},
${0},
${Date.now()}
)
`);
denomination = 0;
}else{
withdrawn = withdrawn + denomination;
await db.query(
sql`DELETE FROM Tenderizer.Withdrawals WHERE ID = ${withdrawals[x]['ID']}`
);
await db.query(sql`
INSERT INTO Tenderizer.Points (GenerationTag, Owner, Denomination, BoughtPoint, Since)
VALUES (
${withdrawals[x]['GenerationTag']},
${request.body.custom},
${withdrawals[x]['Denomination']},
${bsr},
${Date.now()}
)
`);
await db.query(sql`
INSERT INTO Tenderizer.Payouts (GenerationTag, Owner, DollarValue, Denomination, Processed, Since)
VALUES (
${withdrawals[x]['GenerationTag']},
${withdrawals[x]['Owner']},
${bsr * withdrawals[x]['Denomination']},
${withdrawals[x]['Denomination']},
${0},
${Date.now()}
)
`);
denomination = denomination - withdrawals[x]['Denomination'];
}
}
}
if(denomination > 0){
await db.query(sql`
INSERT INTO Tenderizer.Pool (GenerationTag, Username, DollarValue, Withdrawn, Since)
VALUES (
${gt},
${request.body.custom},
${10 - (withdrawn * bsr)},
${0},
${Date.now()}
)
`);
await db.query(sql`
INSERT INTO Tenderizer.Points (GenerationTag, Owner, Denomination, BoughtPoint, Since)
VALUES (
${gt},
${request.body.custom},
${denomination},
${bsr},
${Date.now()}
)
`);
}
await db.query(sql`UPDATE Tenderizer.EHC_Count SET Credits = Credits + ${7 / bsr} WHERE Username = ${request.body.custom}`)
}
};
P.S. it also looks like you're forgetting to actually declare your variables (using let or const before you assign values to them.
P.P.S doing all these queries in a loop may be quite slow, because each one will be executed sequentially. This will be necessary if each query depends on the result of the previous one, but if that's not the case, you could replace one/all of the loops with await Promise.all(list.map(async (value, index) => {...})), which will run the function for each value in the list, but will run it in parallel.

Node.js + SQL - is Insert query faster than Select?

I have a problem with SQL in node.js.
I have an array 'data' which contains some data returned from the async function and I want to put it into MySQL database if there's no result with the same data. There are some duplicated objects in array but I want to put just one into database.
Function example:
async function data_name(param){
var data = [];
data.push({
name: param,
sname: 'sname',
url: 'url',
report: 'report'
});
return data;
}
Then I run following code:
var data = await data_name('name');
data.forEach(item=>{
var chk = "SELECT * FROM `?` WHERE `name` = ? AND `sname` = ?;";
con.query(chk, [tablename, item.name, item.sname], function(er,items){
if(er) throw er;
if(items.length < 1){
var insert = "INSERT INTO `?` (name, sname, url, report) VALUES (?,?,?,?)";
con.query(insert, [tablename, item.name, item.sname, item.url, item.report], function(erg,added){
if(erg) throw erg;
console.log('Item added: ' + item.name);
});
}
else{
if(items[0].report != item.report){
var upd = "UPDATE `?` SET report = ? WHERE id = ?";
con.query(upd, [tablename, item.report, items[0].id], function(ere,edited){
if(ere) throw ere;
console.log('Item updated: ' +items[0].name);
});
}
}
//broken code below
var adc = "SELECT * FROM `links` WHERE `link` = ?;";
con.query(adc, item.url, function(erc, results){
//tried also with: results[0] === undefined || results[0] === null
var test = item.url + ' ' + results.length;
console.log(test);
if(results.length < 1){
var add_c = "INSERT INTO `links` (link_name, link_url) VALUES (?,?)";
con.query(add_c, [item.name, item.url], function(era, a_link){
if(era) throw era;
});
}
else{console.log('Record exists');}
});
});
});
The first SQL works great: it inserts all records to database, there are no duplicates and it updates values if it is required.
Second SQL (mentioned by a comment in code that I put before) doesn't work properly if the database is empty. It duplicates records in database (after running it database has 470 records while every record is duplicated about 8 times).
test variable prints for eg:
https://google.com 0
https://google.com 0
https://facebook.com 0
https://facebook.com 0
https://google.com 1
https://facebook.com 0
https://google.com 0
The problem exists only if a database is empty (if I run the code second time, the second SQL doesn't insert records new records and print in console 'Record exists'
Any ideas what can be reason of that?

perform async multiple Mysql queries on Node

I'm using node with Mysql and here's my problem.
I'm trying to add new photos on my database and return it as an array
here is my function :
function addNewPhotos(_id, files) {
var deferred = Q.defer();
var new_photos = []
_.each(files, function (one) {
var data = [
one.path,
_id,
0
]
var sql = 'INSERT INTO photos(photo_link, id_user, isProfil) VALUES (?, ?, ?)';
db.connection.query(sql, data, function (err, result) {
if (err)
deferred.reject(err.name + ': ' + err.message);
var sql = 'SELECT id_user, photo_link, isProfil FROM `photos` WHERE id = ?';
if (result){
db.connection.query(sql, [result.insertId], function(err, photo) {
if (err) deferred.reject(err.name + ': ' + err.message);
if (photo) {
new_photos.push(photo[0]);
}
});
}
})
})
deferred.resolve(Array.prototype.slice.call(new_photos));
return deferred.promise}
The Insert works well but i can't retrieve the results to send them back to the client. (my array is empty)
Thanks.
Always promisify at the lowest level, in this case db.connection.query().
if(!db.connection.queryAsync) {
db.connection.queryAsync = function(sql, data) {
return Q.Promise(function(resolve, reject) { // or possibly Q.promise (with lower case p), depending on version
db.connection.query(sql, data, function(err, result) {
if(err) {
reject(err);
} else {
resolve(result);
}
});
});
};
}
Now the higher level code becomes very simple :
function addNewPhotos(_id, files) {
var sql_1 = 'INSERT INTO photos(photo_link, id_user, isProfil) VALUES (?, ?, ?)',
sql_2 = 'SELECT id_user, photo_link, isProfil FROM `photos` WHERE id = ?';
return Q.all(files.map(function(one) {
return db.connection.queryAsync(sql_1, [one.path, _id, 0]).then(function(result) {
return db.connection.queryAsync(sql_2, [result.insertId]);
});
}));
};
To prevent a single failure scuppering the whole thing, you might choose to catch individual errors and inject some kind of default ;
function addNewPhotos(_id, files) {
var sql_1 = 'INSERT INTO photos(photo_link, id_user, isProfil) VALUES (?, ?, ?)',
sql_2 = 'SELECT id_user, photo_link, isProfil FROM `photos` WHERE id = ?',
defaultPhoto = /* whatever you want as a default string/object in case of error */;
return Q.all(files.map(function(one) {
return db.connection.queryAsync(sql_1, [one.path, _id, 0]).then(function(result) {
return db.connection.queryAsync(sql_2, [result.insertId]);
}).catch(function() {
return defaultPhoto;
});
}));
};
Do the return in your async loop function when all has been done
function addNewPhotos(_id, files) {
var deferred = Q.defer();
var new_photos = [];
var todo = files.length;
var done = 0;
_.each(files, function (one) {
var data = [
one.path,
_id,
0
]
var sql = 'INSERT INTO photos(photo_link, id_user, isProfil) VALUES (?, ?, ?)';
db.connection.query(sql, data, function (err, result) {
if (err)
deferred.reject(err.name + ': ' + err.message);
var sql = 'SELECT id_user, photo_link, isProfil FROM `photos` WHERE id = ?';
if (result){
db.connection.query(sql, [result.insertId], function(err, photo) {
if (err) deferred.reject(err.name + ': ' + err.message);
if (photo) {
new_photos.push(photo[0]);
}
if(++done >= todo){
deferred.resolve(Array.prototype.slice.call(new_photos));
return deferred.promise
}
});
}
else
{
if(++done >= todo){
deferred.resolve(Array.prototype.slice.call(new_photos));
return deferred.promise;
}
}
})
})
}