I need to create a mysql connection in nodejs , but the credentials for the mysql comes from a third party credential manager service. Can somebody suggest me a way to achieve this?
database.js - i am using connection from this file in all other database operations
const mysql = require("mysql");
const {env} = require('./globals')
const connection = mysql.createConnection({
host: env.DATABASE.HOST,
user: env.DATABASE.USER,
password: env.DATABASE.PASSWORD,
database: env.DATABASE.NAME,
multipleStatements: true
});
connection.connect(function (err) {
if (err) {
console.log("Error in DB connection");
console.log("err", err);
} else console.log("Connected!");
});
module.exports = connection
globals.js
const {getSecret} = require('../src/service')
require("dotenv").config();
async function getCredentials() {
const result = await getSecret()
return JSON.parse(result?.SecretString || {})
}
const credentials = getCredentials() // not working, and i can't use await here
const env = {
DATABASE: {
HOST: credentials.ip_address,
PASSWORD: credentials.password,
NAME: credentials.dbname,
USER: credentials.username,
},
SKU: process.env.SKU
}
module.exports.env = env
Your 2 main options are:
Don't export connection but export an async function that returns a connection.
Write an init() function that sets up your database connection, and ensure it's one of the first things your application calls before anything else.
Well first, you need to fix up that globals.js file. Logic that depends on an async function must be async itself. You can just move everything into the async function like so:
const {getSecret} = require('../src/service')
require("dotenv").config();
async function getCredentials() {
const result = await getSecret()
const credentials = JSON.parse(result?.SecretString || {})
return {
DATABASE: {
HOST: credentials.ip_address,
PASSWORD: credentials.password,
NAME: credentials.dbname,
USER: credentials.username,
},
SKU: process.env.SKU
}
}
module.exports = { getCredentials }
And since even your database connection in database.js depends on this async function, it will have to be async as well:
const mysql = require("mysql");
const {getCredentials} = require('./globals')
const getConnection = getSecret().then(function (env) {
const connection = mysql.createConnection({
host: env.DATABASE.HOST,
user: env.DATABASE.USER,
password: env.DATABASE.PASSWORD,
database: env.DATABASE.NAME,
multipleStatements: true
});
connection.connect(function (err) {
if (err) {
console.log("Error in DB connection");
console.log("err", err);
} else console.log("Connected!");
});
return connection;
})
module.exports = getConnection
Related
config.js
const mysql = require('mysql2');
const config = {
host: 'localhost',
port: '3306',
user: 'root',
password: 'root',
database: 'krometal',
charset: "utf8mb4_bin",
multipleStatements: true
};
const connection = mysql.createPool(config);
connection.getConnection(function (err, connection) {
//connecting to database
if (err) {
logger.log('error', err);
console.log("MYSQL CONNECT ERROR: " + err);
} else {
logger.log('info', "MYSQL CONNECTED SUCCESSFULLY.");
console.log("MYSQL CONNECTED SUCCESSFULLY.");
}
});
module.exports = {
connection
}
login.js
const loginUser = async (req, callback) => {
connection.query(sql, async function (err, rows) => {
// logic
callback(result, 401, connection);
})
}
route.js
users.post('/users/login', async (req, res) => {
await loginUser(req, async (response, code, connection) => {
await connection.end();
res.status(code).send(response);
});
});
The problem is the first time I try login worked fine, but if I try the same login API again throw the error Error: Pool is closed.
Should I use the
connection.end()
method every time I open connection or mysql2 automatically end connection?
Don't run
await connection.end();
After running this function you need to create a new connection using
connection.getConnection();
Having the following code
connection.js
import pkg from "pg";
const { Client } = pkg;
let connection = undefined;
export async function connect() {
const client = new Client({
user: "postgres",
host: "localhost",
database: "dbname",
password: "password",
port: "5432",
});
connection = await client.connect();
}
export async function query(text, values) {
try {
await connection.query(text, values);
} catch (error) {
console.error(error.message);
}
}
I intend that when calling the connect function a value is assigned to the connection variable that will then be used in the query function
This is how I call the connect method
index.js
import { connect } from "./src/connection.js";
import { handleStep1 } from "./src/step1.js";
async function init() {
await connect();
await handleStep1();
}
init();
And I intend to call the query function from another file as follows
step1.js
import { query } from "./connection.js";
export async function handleStep1() {
const results = await query("SELECT * FROM public.user", []);
console.log(results);
}
But here when calling the query function it gives me the following error message Cannot read property 'query' of undefined
What is the correct way to assign a value to a variable that will later be used in different script calls?
Thanks in advance
You can simply export a variable which is intialized and import it anywhere you want.
export async function connect() {
const client = new Client({
user: "postgres",
host: "localhost",
database: "dbname",
password: "password",
port: "5432",
});
connection = await client.connect();
}
export async function query(text, values) {
try {
await connection.query(text, values);
} catch (error) {
console.error(error.message);
}
}
// export let connection = connect();
// import it in other files. like import{ connection } from from "./connection.js";
//if you need to all connect only once. just update the line to
let connection = connect(); //remove the connection imports in other files.
I'm sorry, but I used a translator. I hope you understand.
I got curious while using mysql module. look at the code first.
db_promise.js
Create a pool.
const mysql = require('mysql2');
const config = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PW,
database: process.env.DB_NAME,
connectionLimit: 100,
queueLimit: 10000,
multipleStatements: true,
waitForConnections: true,
dateStrings: 'date'
}
const createPool = mysql.createPool(config, (err)=>{
console.error(err);
});
const pool = createPool.promise();
module.exports = pool;
run.js
Function A creates a connection, passes it to Function B after use, and continues to use it.
const pool = require('./db_promise.js');
const A = async ()=>{
let conn;
try {
conn = await pool.getConnection();
await conn.query('do stuff1..');
await B(conn);
return;
}catch(e){
console.error(e);
} finally {
conn.release();
}
}
const B = async (conn)=>{
try {
await conn.query('do stuff2..');
return;
}catch(e){
throw e;
}
}
creating connections for each function would be a waste. Can only one connection be reused when it is an associated function?
I am trying to connect my application to the database using the connection pool method, its connecting fine, and data insertion is happening fine without any issues but other queries in the same file are slowing down.
I have tried with release() method also not working properly.
How can release the pool to the next query once it's executed the current query?
Below is my dbpool.js file code where I am writing a common generalized database connection,
var pg = require('pg');
var PGUSER = 'postgres';
var PGDATABASE = 'test_database';
var config = {
user: PGUSER, // name of the user account
host: 'localhost',
database: PGDATABASE, // name of the database
password: 'password#AWS',
port: 5432,
max: 10,
idleTimeoutMillis: 10000
};
const pool = new pg.Pool(config);
const DB = {
query: function(query, callback) {
pool.connect((err, client, done) => {
if(err){ return callback(err); }
client.query(query, (err, results) => {
// done();
client.release();
// if(err) { console.error("ERROR: ", err) }
if(err) { return callback(err); }
callback(null, results.rows);
})
});
}
};
module.exports = DB;
I tried with both the done() and client.release() method but no luck. If I use both then I am getting an error message client is already released.
Below is my socket.js file code:
var express = require('express');
const connection = require('./dbpool.js');
if(arData == '0022'){
const queryText = "INSERT INTO alert(alert_data) VALUES('"+arData+"')";
connection.query(queryText,(err, res) => {
if(err){
console.log(err.stack);
}
});
}
if(arData == '0011'){
const queryText = "INSERT INTO table2(alert_data) VALUES('"+arData+"')";
connection.query(queryText,(err, res) => {
if(err){
console.log(err.stack);
}
});
}
function ReverseCommunication(){
const select1 = "SELECT * FROM alert WHERE action = '0' ORDER BY alert_id ASC LIMIT 1";
connection.query(select1, (err, res) =>{
if(err) {
console.log("Error1");
res.json({"error":true});
}
else{
console.log("res==",res);
}
});
}
setInterval(function(){
ReverseCommunication();
}, 2000)
With pool you shouldn't need to close the connection. With pool it will reuse the connection pool for subsequent request so you don't have to connect to the DB each time.
(i'm not a PG expert here, sure other could expand on that way better then I )
What works for us is to set up the dbpool file you have like this
const {Pool,Client} = require('pg');
const pool = new Pool({
user: process.env.POSTGRES_USER,
host: process.env.POSTGRES_URL,
database: process.env.POSTGRES_DATABASE,
password: process.env.POSTGRES_PASSWORD,
port: process.env.POSTGRES_PORT,
keepAlive: true,
connectionTimeoutMillis: 10000, // 10 seconds
max: 10
});
pool.connect()
.then(() => console.log('pg connected'))
.catch(err => console.error(err))
module.exports = pool
Then use the pool.query like you have now with pool.connect
Also, just a side note what lib are you using for PG? Noticed your queries are dynamic, you may want to adjust those to prevent possible SQL-injection.
So I'm trying to make it so I don't have to have multiple connections to my database when I can just put my connection and runQuery function in a file and just require it in another file. Here is what I have in my "mysql.js" file.
const mysql = require('mysql');
module.exports = function () {
let connection = mysql.createConnection({
host: '------',
user: 'voltclou_site',
password: '----',
database: process.env.database
})
connection.connect(function(err) {
if (err) {
console.error('[DATABASE] Error connecting: ' + err.stack);
return;
}
console.log('[DATABASE] Connected as id ' + connection.threadId);
});
async function runQuery(query, values) {
return new Promise((resolve, reject) => {
connection.query(query, values, function (error, results) {
if (error) return reject(error)
return resolve(results)
})
})
}
}
Here is how I would like to require it in my files:
const { connection, runQuery } = require('./functions/mysql')
Am I doing this correctly? I'm new to this whole module thing. I've been trying to split my files up because one index.js with 3000+ lines is insane. Thanks for any help.
No you didnt do it correclty. What you have done you have exported it as an default but you want to export named functions. You can do it like:
const mysql = require("mysql");
let connection = mysql.createConnection({
host: "81.19.215.6",
user: "voltclou_site",
password: "yogO{6,F#8WS",
database: process.env.database
});
connection.connect(function(err) {
if (err) {
console.error("[DATABASE] Error connecting: " + err.stack);
return;
}
console.log("[DATABASE] Connected as id " + connection.threadId);
});
async function runQuery(query, values) {
return new Promise((resolve, reject) => {
connection.query(query, values, function(error, results) {
if (error) return reject(error);
return resolve(results);
});
});
}
module.exports = {
connection,
runQuery
};
The value you've described, { connection, runQuery }, should be the value assigned to module.exports:
const mysql = require('mysql');
let connection = mysql.createConnection({ ... });
connection.connect(...);
let runQuery = async (query, values) => { ... };
module.exports = { connection, runQuery };
You may not even need to export connection, if all you need elsewhere is runQuery!