i want to simply handle error and get insertId after created new row on database, in my code which i get help from mysqljs/mysql official page, i can't do them, how can i fix my code to do them?
var post = {deviceImei: deviceInformation.deviceImei, created_at: currentDateTime, updated_at: currentDateTime};
var query = connection.query('INSERT INTO users SET ?', post, function (err, result) {
if (err)
throw err;
return result;
});
query.on('error', function (err) {
console.log(err)
}).on('fields', function (fields) {
console.log(fields)
}).on('result', function (row) {
console.log(row.insertId);
}).on('end', function () {
// all rows have been received
});
after insert or get some error i cant any message on shell by console
The correct way to do that is documented here:
connection.query('INSERT INTO users SET ?', post, function(err, result) {
if (err) throw err;
console.log(result.insertId);
});
You can use native ES6 promises supported in newest versions of node
var insertQuery = function(post) {
return new Promise(function(resolve, reject) {
connection.query('INSERT INTO users SET ?', post, function (err, result) {
if (err)
reject(error);
resolve(result);
}
});
}
The you can handle after
insertQuery(post)
.then(function(result) {
console.log(result.inserId);
})
.catch(function(error) {
console.log(err);
})
There are libs like 'q' or 'bluebird' which are easy to use too
Related
In the below code, users.push used within ‘db.each’ wont work. However, if I move ‘users.push’ outside then it seems to work.
How can I push the new objects from db.each into the users array?
let db = new sqlite3.Database('./db/main.db', (err) => {
if (err) console.error(err.message);
console.log('Connected to the main database.');
});
var users = [];
db.serialize(() => {
db.each(`SELECT email, name FROM users`, (err, row) => {
if (err) console.error(err.message);
let user = {
email: row.email,
name: row.name
}
users.push(user);
});
});
console.log(JSON.stringify(users));
db.close();
I am using express and sqlite3 node packages.
It's because db.serializeand db.each are asynchronous functions (and return immediately, thus executing console.log before the db callbacks are executed).
Here should be a working example :
db.serialize(() => {
db.each(`SELECT email,
name
FROM users`, (err, row) => {
if (err) {
console.error(err.message);
}
let user = {
email : row.email,
name : row.name
}
users.push(user);
console.log(JSON.stringify(users));
db.close();
});
});
First error: asynchronicity not handled properly
As Antoine Chalifour pointed out, you call console.log(JSON.stringify(users)); before users gets modified in the asynchronous callback. Refer to his answer for fix and explanations.
Second error: errors not handled
You wrote if (err) { console.error(err.message); } then go on with the rest of the function. That is bad, because an error might happen and you'd just continue with your program. You should instead write something like:
if (err) {
console.error(err);
return;
}
or:
if (err) throw err;
I'm having trouble understanding how to create functions that would return in the format of (err, result) for an Express app.
My current db query function is:
pool.query(
'SELECT id FROM users WHERE email = ? LIMIT 1',
[email],
(results) => { // I'd like this to be (err, results)
if(results instanceof Error){...}
}
})
In my db.js file, pool looks like this:
module.exports = {
query: (query, args, cb) => {
pool.getConnection( (err, connection) => {
if(err){
new Error('No database connections available in pool')
} else {
connection.query(query, args, (error, results, fields) => {
connection.release()
// I got a MySQL error here and I'd like to handle it in my callback function
if(error){
new Error('Bad query')
} else {
cb(results)
}
})
}
})
}
}
For this and other functions, I'd like to return a proper Error if there is one, and have my callback listen for err, result as parameters.
I tried using new Error('Bad query') but that came back as the first variable in my callback no matter what (which is how I ended up with instanceof Error.
How do you structure a callback and response so that your callback can be in the err, result format and check for/handle errors properly on functions you're creating? (I understand how to use it for modules already in this format - I'm talking about writing/formatting your own code.)
Thanks!
You can do it like this:
module.exports = {
query: (query, args, cb) => {
pool.getConnection( (err, connection) => {
if(err){
cb(new Error('No database connections available in pool'));
} else {
connection.query(query, args, (error, results, fields) => {
connection.release();
// I got a MySQL error here and I'd like to handle it in my callback function
if(error){
cb(new Error('Bad query'));
} else {
cb(null, results);
}
});
}
});
}
}
You always pass the error value as the first argument to the callback and, if there is a result, you pass it as the second. Then, within the callback, you check to see if err is non-null and, if so, there is an error. If it's null, then the second argument contains the result.
Note that by not returning or including the actual err value that the database gave you, you may be hiding useful information (like why the query failed).
Then, where you use this, you do something like this:
let query = 'SELECT id FROM users WHERE email = ? LIMIT 1';
pool.query(query, [email], (err, result) => {
if (err) {
// handle error here
} else {
// process result here
}
});
The concept of promises is very new for me (so far, I was working with async.each and async.waterfall)
I want to use promises but i'm stuck right now.
I want to get "tags" from my db.
I have two tables for this : One called 'tags' with every tag in it (with an ID) and another one 'user_tags' with every username saved and the ID of the tag that the user (username) created and saved into 'tags'.
I can put information in my DB but now I want to pull this out and log it out (I will display it later)
So far this is my idea :
var getUserprofile = function getUserprofile(username, callback){
pool.getConnection(function (err, connection) {
var dataUser = [];
// Error check
if (err) {
console.log(err);
}
connection.query('SELECT * FROM users_tags FULL JOIN tags ON (tags.id = users_tags.t_id) WHERE users_tags.user_id=666;', username , function (err, rows, fields) {
if (err) {
connection.release();
cb(err);
} else if (rows.length < 1) {
connection.release();
cb("We don't have any informations about this user yet");
} else {
console.log("we pull the information right now");
connection.release();
callback(null, rows[0]);
}
});
});
}
Is this a good idea ? What should I do if I want to use promises for this kind of function ?
Thanks in advance for any help !!!
I would use Bluebird. You can "promisify" existing APIs with Promise.promisify or Promise.promisifyAll.
I would do something like
var Promise = require('bluebird'),
... //other deps;
var pool = Promise.promisifyAll(pool);
function getUserprofile(username){
var connection = null;
return pool.getConnectionAsync()
.then(function (conn) {
connection = Promise.promisifyAll(conn);
return connection.queryAsync('...');
})
.then(function (results) {
if (results.length < 1) {
return "We don't have any informations about this user yet";
} else {
console.log("we pull the information right now");
return results[0];
}
})
.catch(function (err) {
console.log(err);
throw err;
})
.finally(function () {
if (connection) {
connection.release();
}
});
}
I'm wondering if this approach is correct or does it need further refinements, maybe promisify custom mySQL getConnection method as well???
request: function(queryRequest) {
return new Promise(function(resolve, reject){
Database.getConnection(function(error, connection){
if(error) {
reject({error: error, queryRequest: queryRequest});
} else {
connection.query(queryRequest.sql, queryRequest.values, function(error, rows, fields){
if(error) {
reject({error: error, queryRequest: queryRequest});
} else {
resolve({rows: rows, fields: fields, queryRequest: queryRequest});
}
});
}
});
});
},
The getConnection method defined in Database module.
getConnection: function(callback) {
this.pool.getConnection(function(error, connection){
callback(error, connection);
});
},
maybe promisify custom mySQL getConnection method as well?
Only maybe. While it could be considered a bit cleaner, and makes your callback pyramid a bit flatter, it doesn't improve the code much:
function request(queryRequest) {
return new Promise(function(resolve, reject) {
Database.getConnection(function(error, connection) {
if (error)
reject(error);
else
resolve(connection);
});
}).then(function(connection) {
var res = new Promise(function(resolve, reject) {
connection.query(queryRequest.sql, queryRequest.values, function(error, rows, fields) {
if (error)
reject(error);
else
resolve({rows: rows, fields: fields, queryRequest: queryRequest});
});
});
return res;
}).catch(function(error) {
throw {error: error, queryRequest: queryRequest};
});
}
I'm wondering if this approach is correct
For database connections, you might want to have a look at the disposer pattern. If you don't need it, you still should remember to always release your connections, using something like
….then(function (connection) {
var res = …;
// better be solved using `finally` where supported
return res.then(end, end);
function end() {
connection.release();
return res;
}
})
Also, rejecting promises with objects that are no Errors is a bad practise, you might better do
….catch(function(error) {
error.queryRequest = queryRequest;
throw error;
})
or the equivalent in your original pattern.
How do you do a "join" (i know it is not the correct term) with an array of messages in mongoose?
I tried looping over all the messages and querying to get the user info but it is not working:
messages.forEach(function (message, index) {
User.findById(message.userId, function (err, user) {
messages[index].user = user
})
})
console.log(messages) // the user info is not attatched
So how is this accomplished with mongoose and node.js?
the biggest problem with your code is, that you assume the code to run synchronously - but it doesn't. it runs asynchronously. so messages is not yet set when you execute
console.log(messages);
do something like this instead:
var userIds = [id1, id2, id3];
User.find({"_id": {$in: userIds}}, function (err, users) {
console.log(users);
});
edit
ok, i see. you want to add the userInfo to the different messages.
easiest way to acieve this, is to use the async module: https://github.com/caolan/async
async.map(messages, getUserInfo, function (err, result) {
if (err) {
console.log(err);
return;
}
// log all msg with userinfo
console.log(result);
});
function getUserInfo (msg, callback) {
User.findById(msg.userId, function (err, user) {
if (err) {
callback(err);
return;
}
msg.user = user;
callback(null, msg);
});
}