I think I'm having some async issues with implementing a function that gets all rows from a table in a mysql database using node js. I'm using the node-mysql module.
I have already googled this, and have tried doing the accepted answer on this question says but still no luck. It tells me undefined is not a function on the throw err. Anyone know what the issue here is?
var express = require('express');
var mysql = require('mysql');
var router = express.Router();
router.get('/people', function(req, res, next) {
getAllPeople(function(err, people) {
res.json(people);
});
});
function getAllPeople(cb) {
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'people'
});
connection.connect();
connection.query('SELECT * from people', function(err, rows, fields) {
connection.close();
cb(err, rows);
});
}
module.exports = router;
There is no close() method defined in connection object. Use connection.end()
Related
I'm new to javascript and node.js.
Can someone answer the following questions.
1. How I split the PostgreSQL part properly in an other file.
2. How I the pest practice is to use the pg pools.
3. How I improve this code for production.
const express = require('express');
const app = express();
const pg = require('pg');
const pool = new pg.Pool({
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
});
app.get('/api/recipes', function(req, res){
pool.connect(function(err, client, done) {
if(err){
console.log('Connection failed '+ err);
res.status(400).send(err);
}
client.query('SELECT * FROM recipes;', function(err, result) {
done();
if(err){
console.log('Error with query! ERROR code: ' + err.code);
res.status(400).send(err);
}
else{
res.status(200).send(result.rows)
}
});
});
});
app.get('/api/recipes/:id', function(req, res){
var id = req.params.id;
pool.connect(function(err, client, done) {
if(err){
console.log('Connection failed ' + err);
res.status(400).send(err);
}
else{
client.query('SELECT * FROM recipes WHERE recipes_id = $1;', [id], function(err, result) {
done();
if(err){
console.log('Error with query! ERROR code: ' + err.code);
res.status(400).send(err);
}
else{
res.status(200).send(result.rows)
}
});
}
});
});
app.listen(3000,function(){
console.log('Server listen on port 3000');
});
There are a lot of ways folks go to split the code you've described. I'll take it piece by piece.
First, pull any configurable variables out and setup one file that can get them from the environment (possibly with dev defaults in place, your choice on that). You can use a library like commander or convict, but honestly I prefer to just write a simple file that pulls them myself:
// ./config.js
module.exports = {
pool: {
user: process.env.DB_USER || 'admin',
password: process.env.DB_PW || 'test123!',
host: process.env.DB_HOST || '127.0.0.1',
port: process.env.DB_PORT || '5432',
database: process.env.DB_NAME || 'test_db'
}
};
As for your database calls, some folks like to use ORM-like stuff such as sequelize, but again I tend to start simple and add things as needed. In your case, you should think about what boilerplate stuff you can make common code around, and then wrap those into simple modules that only expose to the calling code stuff it really needs. For example, you will note that most of your routes are going to connect to the pool, test for an error, then run a query if it doesn't error out, and finally render either the error or query results, right? So that can all be wrapped into a fairly simple query function that handles the boilerplate internally and works with just a query expression and a callback, for example:
// ./db/index.js
const pg = require('pg');
const config = require('./config');
const pool = new pg.Pool(config.pool);
function query(sql, params, callback) {
// maybe check for valid inputs here or something, but at least normalize in case folks don't pass params
if(arguments.length < 3) {
callback = params;
params = null;
}
pool.connect((err, client, done) => {
// just exit here and let the calling code know there was a problem
if(err) return callback(err);
// I haven't tested this w/ the pg library recently, you might have to do two of these if it doesn't like null as a second argument
client.query(sql, params, (err, result) => {
if(err) return callback(err);
done();
// calling code probably doesn't care about anything but rows, but you can do other stuff here if you prefer
return callback(null, result.rows);
});
});
};
// You can also add additional functions if you want shorthand for doing things like query by ID or with params, or similar
module.exports = { query };
I also think that it can be helpful to store the SQL strings somewhere centrally, or on model objects, just to make the routing code note have to care about that. For a super simple example using your two routes, I might do something like this:
// ./db/queries.js
module.exports = {
RECIPES: {
LIST: 'SELECT * FROM recipes;',
FIND_BY_ID: 'SELECT * FROM recipes WHERE recipes_id = $1;'
}
};
Ok, so now your routing code can be quite simple, you can just get the db module and work the query, letting the routing worry just about what it's got to do with the request and response. Another option that folks like is to actually create a module for each model in your app (e.g. a Recipe) that wraps the above two files into a set of static functions so that your routes don't even know they're querying specifically. The calls in that case would be something like Recipe.list(cb) or Recipe.findById(id, cb). This is a style made popular by Ruby on Rails a few years ago, it has mixed acceptance in the Node community, but I'm mentioning it for completeness.
// ./routes/recipes.js
const router = require('express').Router();
const db = require('./db');
const queries = require('./db/queries');
router.get('/api/recipes', (req, res, next) => {
db.query(queries.RECIPES.LIST, (err, rows) => {
if(err) return next(err);
return res.send(rows); // status 200 is the default here
});
});
router.get('/api/recipes/:id', (req, res, next) => {
const id = req.params.id;
db.query(queries.RECIPES.FIND_BY_ID, [id], (err, rows) => {
if (err) return next(err);
return res.send(rows);
});
});
Finally, in your main Express setup file:
// ./app.js
const express = require('express');
const app = express();
const recipeRoutes = require('./routes/recipes') // note if you have an index.js file that gets imported just by calling for the folder, so that's a way to group features as well
app.use(recipeRoutes);
// I'm a big fan of error handling middleware. There's a more complex approach I did in [praeter][4] that gives you http-verb based errors that you can then catch and send the appropriate status, but that's again more complex than you might need here.
app.use((err, req, res, next) => {
// this can be as simple or as complex as you like.
// note it's a best practice to send only "clean" messages to the client, so you don't give away that you're using a Postgres db or other stuff that makes hacking easier.
console.error(err);
res.status(500).send('Oops! Something went wrong!!');
});
Obviously, there's a lot of ways to skin this cat, so I'd recommend mostly just looking for where you're repeating yourself, and then refactor to repeat less. Also, if you're interested in making more production-ready apps in general, the 12 factor app is a must-read.
To answer number 1,
dbPool.js
const pg = require('pg');
export.pool = new pg.Pool({
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
});
app.js
const express = require('express');
const app = express();
const pool = require('./dbPool');
....
You should create config file and require that file in app.js
--config
----config.js
--app.js
var config = {
production: {
pool: {
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
}
},
development: {
pool: {
user: 'admin',
password: 'test123!',
host: '127.0.0.1',
port: '5432',
database: 'test_db'
}
}
}
exports.get = function get(env) {
return config[env] || config.development;
}
I am currently developing a node.js backend for a mobile app with potentially many users. However it's my first time in developing node.js. I was following a tutorial on how to connect to a mysql database via mysql pools.
I am able to create a single mysql connection and do queries via my routes.
The problem arises once I establish the file structure mentioned in the tutorial:
dbConnect
-[models]
--users.js
-db.js
-server-ks
I am not getting an error message regarding the connection of the mysql database - even if I enter a wrong password.
// server.js
///////////////////////////// basic setup ///////////////////////////////////
var restify = require('restify');
var bodyParser = require('body-parser');
var mysql = require('mysql');
var db = require('./db');
var users = require('./models/users');
///////////////////////////// initilisation of the server ///////////////////////////////////
var server = restify.createServer({
name: 'testUsers',
});
server.use(restify.bodyParser({ mapParams: true }));
///////////////////////////// Säuberung der URL //////////////////////////////////////////
server.pre(restify.pre.sanitizePath());
///////////////////////////// MySQL Instanz starten //////////////////////////////////////////
db.connect(db.MODE_PRODUCTION, function (err) {
if (err) {
console.log('Unable to connect to MySQL.')
process.exit(1)
} else {
server.listen(8080, function () {
console.log('Listening on port 8080 ...')
})
}
})
///////////////////////////// implementation of the routes ///////////////////////////////////
function send(req, res, next) {
var test = users.getAll();
res.json({ test: 'Hello ' + req.params.name });
return next();
};
My DB.js file looks the following:
var mysql = require('mysql'),
sync = require('async')
var PRODUCTION_DB = 'userDB',
TEST_DB = 'userDB'
exports.MODE_TEST = 'mode_test'
exports.MODE_PRODUCTION = 'mode_production'
var state = {
pool: null,
mode: null,
}
exports.connect = function (mode, done) {
state.pool = mysql.createPool({
connectionLimit: 50,
host: 'localhost',
user: 'user',
password: 'password',
database: 'userDB' // test
//mode === exports.MODE_PRODUCTION ? PRODUCTION_DB : TEST_DB
})
state.mode = mode
done()
}
exports.get = function () {
return state.pool
}
Could it be, that the tutorial spared out an essential part in utilizing mysql pools and node.js?
Thanks in advance for at least trying to answer that question.
Are there better methods sequelize(?) available to create performant connections to a MySQL database?
It looks like creating the pool object does not actually connect to the database. A big clue is that the createPool function is not asynchronous, which is what you would expect if it was actually connecting at that moment.
You have to make use of the returned pool object to perform a query, which IS asynchronous.
From the documentation:
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'example.org',
user : 'bob',
password : 'secret',
database : 'my_db'
});
pool.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
if (err) throw err;
console.log('The solution is: ', rows[0].solution);
});
I'm studying Node.js + Express, coding a basic login example. My /login route is set inside the routes/login.js file:
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var connectionpool = mysql.createPool({
host : 'localhost',
user : 'user',
password : 'pass',
database : 'database'
});
router.post('/', function(req,res){
connectionpool.getConnection(function(err, connection) {
if (err) {
console.error('CONNECTION error: ',err);
res.statusCode = 503;
res.send({
result: 'error',
err: err.code
});
} else {
// Do something
}
});
});
module.exports = router;
I was wondering: how can I make the mysql or the connectionpool visible in the entire application? I don't want to redeclare them on each route file I'll create. I'm looking something like an include or require method.
Any idea?
Create a separate module to act as an interface to retrieving SQL connections like so:
var mysql = require('mysql');
var connectionpool = mysql.createPool({
host : 'localhost',
user : 'user',
password : 'pass',
database : 'database'
});
exports.getConnection = function (callback) {
connectionpool.getConnection(callback);
};
Then in another file:
var connections = require('./connections');
connections.getConnection(function (err, c) {
// Use c as a connection
c.query("select * from table limit 10 ",function(err,rows){
//this is important release part
c.release();
if(!err) {
console.log(rows);
}
});
});
I want to create a manager to interact with mysql, but I'm not able to bring it into the main program. I'm mainly just trying to get the hang of javascript for this stuff (java, c background).
I have two files called main.js and MSYQLConnector.js. I want to use MYSQLConnector from
main.js
var root = __dirname, express = require('express');
var app = express();
var sql = require('./DBConnectors/MYSQLConnector.js');
var a = sql.sqlTest;//????? fail....
MYSQLConnector.js
var sqlTest = function (){
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'xxxx'
});
connection.connect();
connection.query('SELECT * from asset', function(err, rows, fields) {
if (err) throw err;
console.log('The solution is: ', rows[0].solution);
});
connection.end();
};
How can I do the import? Thanks
You need to export the function from your module. Add:
exports.sqlTest = sqlTest;
to the bottom of your MYSQLConnector.js file.
Also, see the nodejs api documentation for more details.
you're almost there, add "exports" in front of it:
exports.sqlTest = function (){
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'xxxx'
});
connection.connect();
connection.query('SELECT * from asset', function(err, rows, fields) {
if (err) throw err;
console.log('The solution is: ', rows[0].solution);
});
connection.end();
};
I'm trying build rest-like API using mongodb(with mogoose) and node.js with restify.
I'm an absolute novice in the mongo world, and I'm not sure where problem is. Is this the db connection's problem, or something else?
So, I'm doing it this way:
rest-server.js
//start server
var restify = require('restify');
var server = restify.createServer();
server.use(restify.bodyParser());
//connect db
var config = require('./Config.js');
var mongoose = require('mongoose'),
db = mongoose.createConnection('localhost', 'travelers'),
Schema = mongoose.Schema,
ObjectId = mongoose.SchemaTypes.ObjectId;
db.on('error', console.error.bind(console, 'DB connection error:'));
db.once('open', function callback() {
console.log('db connection open');
});
var LoginModel = require('./models/LoginModel.js').make(Schema, mongoose);
var LoginResource = require('./resource/LoginResource.js')(server, LoginModel);
LoginModel.js
function make(Schema, mongoose) {
var LoginSchema = new Schema({
//id: (?)
username: String,
password: String,
traveler_id: Number,
contact_id: Number,
last_login: Date,
token: String
});
return mongoose.model('Login', LoginSchema);
}
module.exports.make = make;
LoginResource.js
exports = module.exports = function (server, LoginModel) {
var LoginRepository = require('../repository/LoginRepository.js');
server.get('/login/:username/:password', function (req, res, next) {
LoginRepository.getLogin(req, res, next, LoginModel);
});
}
LoginRepository.js
function getLogin(req, res, next, LoginModel) {
var query = LoginModel.find({ username: req.params.username, password: req.params.password});
query.exec(function (err, docs) {
console.log('got it!');
res.send(docs);
});
}
test query
curl localhost:8080/login/qqq/www
So I never got to res.send(docs);
Actually, I didn't add anything to the db. I just want to know that the query didn't find anything.
UPDATE:
I don't understand why, but this problem can be solved if I change the db connection code like this:
//connect db
var config = require('./Config.js');
var mongoose = require('mongoose/');
db = mongoose.connect(config.creds.mongoose_auth),
Schema = mongoose.Schema;
(use mongoose.connect and define db and Schema vars as global)
but in this case db.on() and db.once() throw an exception "no such methods".
In other words - problem mmm... solved but I still don't know why.
This looks like a helpful link: server.js example on github
Models that you've created by calling mongoose.model() use Mongoose's default connection pool when executing queries. The default connection pool is created by calling mongoose.connect(), and any queries you make using your created models will be queued up until you call that and it completes.
You can also create separate connection pools (that can have their own models!) by calling db = mongoose.createConnection() like you were originally doing, but you would have to create the models for that using db.model() which is why things weren't working for you originally.