I have a problem where I have an array of objects like this:
[
{
department_id: '6256f8ae6f749617e8167416',
employee_id: '6253ca0c6f749618a8d022af',
employee_number: '1234'
},
{
department_id: '6256f8ae6f749617e8167416',
employee_id_id: '6253ca0c6f749618a8d022af',
employee_number: '1503'
}
]
and would like to use node js and mysql to insert it into a database so I have got this script
Department.assignEmployeetoDepartment = (employees, result) => {
let employees_array = Object.values(rooms);
db.query(
`INSERT INTO department_employee (department_id, employee_id, employee_number) VALUES ?`,
[employees_array],
(err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
console.log("success: ", res);
result(null, res);
}
);
};
when I use the code above, I get
INSERT INTO department_employee (department_id, employee_id, employee_number) VALUES '[object Object]', '[object Object]'
which does not work for obvious reasons.
I tried to stringify the object
and I also tried to use a for loop to iterate over the employees array and it did not work as it says the headers were already sent.
How could I store the array (which can vary in length into the database?
Thanks in advance
The solution I'm suggesting for you will serve you safe if you make your data an array of arrays;
const employeesData = [
[
'6256f8ae6f749617e8167416',
'6253ca0c6f749618a8d022af',
'1234'
],
[
'6256f8ae6f749617e8167416',
'6253ca0c6f749618a8d022af',
'1503'
],
];
Next, prepare your query like this;
const sql = `INSERT INTO images (department_id, employee_id, employee_number) VALUES?`;
You're now ready to run your query liike below;
db
.query(sql, [employeesData])
.then(rows => {
res.status(200).json({
status: "success",
message:"Data inserted successfully"
});
})
.catch(err => {
res.status(500).json({
status: "error",
error: err.message
});
});
You can generate array of values to insert using array's map method like shown below,
employeesData = dataSourceArray.map ( (data) => {
return [
department_id,
employee_id,
employee_number
];
});
As per mysql- Escaping query values
Nested arrays are turned into grouped lists (for bulk inserts), e.g. [['a', 'b'], ['c', 'd']] turns into ('a', 'b'), ('c', 'd')
You probably want to map the values to array, you can't pass array of JSON object to query
db.query(
`INSERT INTO department_employee (department_id, employee_id, employee_number) VALUES ?`,
[employees_array.map(employee => [employee.department_id, employee.employee_id, employee.employee_number])],
(err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
console.log("success: ", res);
result(null, res);
}
);
};
Related
Building a simple ToDo app in React/NodeJS/Express with MySQL. Users join a group ("family" in the code), then tasks are viewable filtered by familyId. To create a task, I first have a query that finds the user's familyId from the Users table, then I want to include that familyId value in the subsequent INSERT query for creating the task row in the Tasks table. My task.model.js is below:
const sql = require("./db.js");
// constructor
const Task = function(task) {
this.title = task.title;
this.familyId = task.familyId;
this.description = task.description;
this.completed = task.completed;
this.startDate = task.startDate;
this.userId = task.userId;
};
Task.create = (task, result) => {
sql.query("SELECT familyId FROM users WHERE userId = ?", task.userId, (err, res) => {
if (err) {
console.log("Error selecting from USERS: ", err);
return result(err, null);
}
sql.query("INSERT INTO tasks (familyId, title, description, completed, startDate) VALUES (?,?,?,?,?)", [result, task.title, task.description, task.completed, task.startDate], (err, res) => {
if (err) {
console.log("Error inserting in TASKS: ", err);
return result(err, null);
}
})
console.log("created task: ", { id: res.insertId, ...task });
return result(null, { id: res.insertId, ...task });
});
};
However, I cannot figure out how to properly use the familyId result of the SELECT query as a parameter in the suqsequent INSERT query. I know the overall syntax works because I can manually plug in an ID value as a parameter and the entire operation completes successfully - I just need to know how to use the resule of the first query in the next.
The way you are using it should work but the problem is you have defined the callback as res but are passing result in the 2nd sql query
sql.query("SELECT familyId FROM users WHERE userId = ?", task.userId, (err, res) => {
if (err) {
console.log("Error selecting from USERS: ", err);
return result(err, null);
}
//res should have the value for the familyId of the given user so in next line pass res not result
sql.query("INSERT INTO tasks (familyId, title, description, completed, startDate) VALUES (?,?,?,?,?)", [res[0].familyId, task.title, task.description, task.completed, task.startDate], (err, res) => {
if (err) {
console.log("Error inserting in TASKS: ", err);
return result(err, null);
}
})
console.log("created task: ", { id: res.insertId, ...task });
return result(null, { id: res.insertId, ...task });
});
SQL returns array in result , so use result[0] to get first Object ,
and then access the object key by result[0].keyName
Task.create = (task, result) => {
sql.query("SELECT familyId FROM users WHERE userId = ?", task.userId, (err, users) => {
if (err) {
console.log("Error selecting from USERS: ", err);
return result(err, null);
}
let familyId = users && users[0] ? users[0].familyId : null;
sql.query("INSERT INTO tasks (familyId, title, description, completed, startDate) VALUES (?,?,?,?,?)", [familyId, task.title, task.description, task.completed, task.startDate], (err, res) => {
if (err) {
console.log("Error inserting in TASKS: ", err);
return result(err, null);
}
})
console.log("created task: ", { id: res.insertId, ...task });
return result(null, { id: res.insertId, ...task });
});
};
I started to develop some Nodejs APIs (with Express) today to retrieve some data from MySQL. I am familiar with some programming languages like Python but not with javascript. My first API is now working, but I'm not sure whether it's optimal or not. I am also not understanding some of its behavior.
The values I would like to retrieve :
label
description
latitude
longitude
photos, an array of id_photos
1), 2), 3), and 4) are unique values from a first MySQL table;
the id_photos of 5) are multiple rows from a second MySQL table.
Here is the code I wrote :
PoI.findById = (idPoI, result) => {
sql.query(`SELECT label,description,ST_Y(geo) AS latitude,ST_X(geo) AS longitude FROM poi WHERE id_poi=${idPoI}`, (err, res1) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
if (res1.length) {
sql.query(`SELECT id_photo FROM photo WHERE id_poi=${idPoI}`, (err, res2) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
console.log("found poi: ", {...res1[0],photo:res2});
result(null, {...res1[0],photo:res2});
return;
});
}
// result({ kind: "not_found" }, null);
});
};
EDIT : As highlighted by nbk in the comments, this code is vulnerable to sql injections. The query now looks like that sql.query('SELECT label,description,ST_Y(geo) AS latitude,ST_X(geo) AS longitude FROM poi WHERE ?', args, (err, res1) => {}) with args = {id_poi: idPoI};
My questions:
Is it a correct way to combine the results from two different MySQL queries ?
The console shows found poi : label: 'Museum...' ........ photo: [ RowDataPacket { id_photo: 1 }, RowDataPacket { id_photo: 2 } ]; Thus, the data from the first query look correctly handled, but the data from the second query appear as "RowDataPacket"; It does not seem to affect the final api output though; Is it an issue ?
If I uncomment result({ kind: "not_found" }, null);, I get ERR_HTTP_HEADERS_SENT, why ?
I am using aws as my backend and i have few aws lambda functions (written in node JS) that are used to insert incoming json data to amazon RDS(mysql) DB. Below is my node js code
var mysql = require('mysql');
var config = require('./config.json');
var pool = mysql.createPool({.../});
exports.handler = (event, context, callback) => {
let inserts = [event.unitID, event.timestamp, event.frequency];
pool.getConnection(function(error, connection) {
connection.query({
sql: 'INSERT INTO device_data (device_id, timestamp, frequency) VALUES (?, ?, ?);',
timeout: 40000,
values: inserts
}, function(error, results, fields) {
connection.release();
if (error) callback(error);
else callback(null, results);
});
});
};
This is the incoming json data
"unitID": "arena-MXHGMYzBBP5F6jztnLUdCL",
"timestamp": 1580915318000,
"version": "1.0.0",
"frequency": [
60.0033,
60.004,
60.0044,
60.0032,
60.005,
60.005,
60.0026,
60.0035,
60.0036,
60.0053
]
}
my frequency has array of values and i am unable to handle that to insert into DB.
Any suggestions. Thanks
if your data is in a variable called json:
console.log(json.frequency.map( (freq) =>[json.unitID,json.timestamp,freq] ))
you can then tweak this to fit your sql to a string that replaces VALUES (?,?,?) with your desired output. e.g.:
const values = json.frequency.map( (freq) => [json.unitID,json.timestamp,freq] );
const sqlString = `'INSERT INTO device_data (device_id, timestamp, frequency) VALUES ${values.map( (row) => `(${row[0]},${row[1]},${row[2]})` ).join(',')}`
and in your code:
connection.query({
sql:sqlString
[...]
Hi I am trying to insert a record into a MySQL DB from a post (using postman to test) for a REST API. I keep receiving a server error. Here is my code (using async and await and expecting a promise in return). Here is the router:
* Creates a new user.
*/
router.post('/', async (req, res, next) => {
const options = {
body: req.body
};
try {
const result = await user.createUser(options);
res.status(result.status || 200).send(result.data);
} catch (err) {
next(err);
}
});
And here is the Service (UPDATED - STILL ERROR):
sql = "INSERT INTO users (AccountHolderUserID, isSubUser, parentUsersID, appBrand, accessLevel, accessToken, tempPassword, email, firstName, lastName) VALUES ?";
values = [
[options.body.AccountHolderUserID, options.body.isSubUser, options.body.parentUsersID, options.body.appBrand, options.body.accessLevel, options.body.accessToken, options.body.tempPassword, options.body.email, options.body.firstName, options.body.lastName]
];
console.log(values);
pool.query(sql, [values], function (error, result, fields) {
if (error) {
reject(new ServerError({
status: 500, // Or another error code.
error: 'Server Error' // Or another error message.;
}));
return
}
resolve({
status: 200,
data: result
});
})
});
}
I added a console log right before the pool.query, and here is the response when I try to post. Data is making it from the form to the query, but getting an Cannot convert object to primitive value Error???
App listening on port 8082!
[
[
'1234, ',
'true,',
'1,',
'1,',
'1,',
'1312,',
'1234,',
'notifications#answeringmobile.com,',
'Nancy,',
'Flannagan'
]
]
TypeError: Cannot convert object to primitive value
Please let me know if anyone knows what I am doing wrong. Thank you!
I think MySQL expects each individual value to have its own question mark. You are passing an array of values expecting that it will substitute the whole VALUES clause, but AFAIK it has never worked this way. The error message says that it expects a primitive value and not an object (not an array, it probably wanted to say).
Try this:
sql = "INSERT INTO users " +
"(AccountHolderUserID, isSubUser, parentUsersID, appBrand, " +
" accessLevel, accessToken, tempPassword, email, " +
" firstName, lastName) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
values = [
options.body.AccountHolderUserID, options.body.isSubUser,
options.body.parentUsersID, options.body.appBrand,
options.body.accessLevel, options.body.accessToken,
options.body.tempPassword, options.body.email,
options.body.firstName, options.body.lastName
];
pool.query(sql, values, ......); // note: just values, no extra square brackets
SOLVED AS FOllOWS:
/**
* #param {Object} options
* #param {Object} options.body Created user object
* #throws {Error}
* #return {Promise}
*/
module.exports.createUser = async (options) => {
return new Promise((resolve, reject) => {
const User = {
"AccountHolderUserID": options.body.ctiAccountHolderUserID,
"isSubUser": options.body.isSubUser,
"parentUsersID": options.body.parentUsersID,
"appBrand": options.body.appBrand,
"accessLevel": options.body.accessLevel,
"accessToken": options.body.accessToken,
"tempPassword": options.body.tempPassword,
"email": options.body.email,
"firstName": options.body.firstName,
"lastName": options.body.lastName
}
console.log(User);
pool.query('INSERT INTO users set ?', User, function (error, result, fields) {
if (error) {
reject(new ServerError({
status: 500, // Or another error code.
error: 'Server Error' // Or another error message.;
}));
return
}
resolve({
status: 200,
data: result
});
})
});
}
I have a json request in this form:
{
"claimNo":["5454545","4554454","45884"]
}
the claimNo could hold any number of items(not restricted). I want to get the values and write a query to fetch data from a mysql db where claimNo = the values in the request.
sample response:
"claims": [
{
"claimNo": "4554454",
"ClaimCause": "gjgiukhknl",
"ClaimAmount": 45550,
},
{
"claimNo": "5454545",
"ClaimCause": "fdfdfdfdf",
"ClaimAmount": 0,
}
]
I can successfully loop through the request and display on terminal or even insert into the db with multiple ORs but that only works for a restricted array length.
req.body.claimNo.forEach(element => {
// console.log(element)
let sql = 'SELECT * FROM claims WHERE claimNo = ?'
connection.query(sql,element,(err, rows, fields) => {
if(!err){
// return res.json({
// success:true,
// errorCode:"",
// errorDescription:"",
// claims:rows
// })
console.log(rows)
}else
console.log(err)
} )
})
If I understand your question correctly, you're looking for a way to query MySQL database for multiple number of claimNo entries, and return the result as a single result.
Using MySQL IN() operator, you can write your query as select * from claims where claimNo in(?)
let sql = 'select * from claims where claimNo in(?)';
let claimNos = req.body.claimNo;
connection.query(sql, claimNos, (err, rows, fields) => {
if(!err){
// return res.json({
// success:true,
// errorCode:"",
// errorDescription:"",
// claims:rows
// })
console.log(rows)
}else
console.log(err)
})
You don't need to send a separate request for each claimNo. You can you the IN operator instead. The following should work:
const claimsNo = claims.map(claim => claim.claimNo);
const sql = 'SELECT & FROM claims where claimNo IN (?)';
connection.query(sql, [ tableName, claimsNo ], (err, rows, fields) =>{
...
});