Sequelize and Node.js: Initializing Multiple Databases On One Server Programmatically - javascript

When I run the server attempting to create two databases (db1 and db2), the system kicks backs this error:
Possibly unhandled SequelizeBaseError: database "db2" does not exist
As a reference, there is similar stackoverflow question on this topic here, however, the author of the solution does not cover the solution to how the server.js file is setup. You will notice I have structured my index.js file similar to their answer.
My models/index.js file and server run and executes scripts properly, yet the second database does not work at all and does not even get initialized.
Can someone provide a solution for the server.js file to accurately initialize two databases in this one server?
The following is the partial code from the models/index.js and server.js files. In the server.js file, I am using .sync to initialize the databases.
server.js
[...]
//sync's sequelize DB and tables
db['db1'].sequelize.sync(function(err){});
db['db2'].sequelize.sync(function(err){});
models/index.js
var databasesArray = ['db1', 'db2']
var databasesObj = {
database: {
db1: {
DBName: 'db1',
User: user,
Password: password,
Config: config,
},
db2: {
DBName: 'db2',
User: user,
Password: password,
Config: config,
}
}
} // EOF databaseObj
for(var i = 0; i < databasesArray.length; ++i) {
var databasePointerToOBJ = databasesArray[i];
var database = databasesObj.database[databasePointerToOBJ]
if(database.DBName == 'db1'){
var sq = new Sequelize(database.DBName, user, password, config)
db['db1'] = {
Sequelize: Sequelize,
sequelize: sq,
Table1: sq.import(__dirname + '/...')
}
}else if(database.DBName == 'db2'){
var sq = new Sequelize(database.DBName, user, password, config)
db['db2'] = {
Sequelize: Sequelize,
sequelize: sq,
Table1: sq.import(__dirname + '/...')
}
}
}
module.exports = db;
--- EDIT ---
The author of the solution was correct. In order for a new database to be created, it must be created prior to being sync'd. As piotrbienias rightly notes, adding the code for adding a new DB in a your initialization script would be the best option. Piotrbienias solution is .js option. The code that worked for me is a .sh option and is as following:
PG_HOST=localhost
PG_PORT=5432
PG_DB=databaseName
PG_USER=ubuntu
PG_PASS='EnterPassword'
sudo -u postgres createdb -U postgres -O $PG_USER $PG_DB

You need to create the database manually before trying to access it via Sequelize - it does not create it if it does not exists. You can use a pg module inside some initialisation script to create the DB via CREATE DATABASE before doing any synchronisation and connection, or simply create it via postgres CLI
const pg = require('pg');
module.exports = function(next){
var connectionData = {
user: 'postgres',
password: 'password',
host: 'localhost'
};
var databaseName = 'db2';
var connectionUri = `postgres://${user}:${password}#${host}/postgres`;
pg.connect(connectionUri, function(err, client, done) {
client.query(`CREATE DATABASE ${databaseName}`, function(error){
// here you can perform some sequelize operations after creating the database
client.end(); // disconnect client
next(); // you can call it with some parameter like Sequelize instance etc.
});
});
};

Related

NodeJS Child process cannot access MySQL Pool object

My intention is upon a file upload the main Node.JS Express backend process will fork a child process which will call a java program to parse the uploaded file and then the NodeJS child will make bulk (100K+) MySQL queries. I want the child to handle the queries because I do not want the parent process to "block." Since both the parent and child processes need access to the MySQL connection I have defined in an external file containing an npm mysql pool.
mysqlConnector.js:
// Load module
var mysql = require('mysql');
// Initialize pool
var pool = mysql.createPool({
connectionLimit : 10,
host : 'localhost',
port: 3306,
user: 'bob',
password: 'my_pass',
database: 'my_db'
});
const doQuery = (query_string) => {
console.log(pool);
pool.query(query_string, function (error, results, fields) {
if (error) throw error;
console.log('in doQuery: query' );
});
};
exports.doQuery = doQuery;
exports.pool = pool
My index.js (main process) is able to access this pool and make queries with no issue. The main process will fork the child running the following code
handleprops.js:
const {execSync, fork} = require('child_process');
const {doQuery} = require('../mysqlConnector');
const exec_options = {
cwd: null,
env: null,
encoding: 'utf8',
timeout: 0,
maxBuffer: 200 * 1024,
killSignal: 'SIGTERM'
};
process.on('message', msg=>{
if(msg.filepath && msg.username){
execSync(`java -jar C:\\Users\\colli\\d2reader\\out\\artifacts\\d2reader_jar\\d2reader.jar ${msg.filepath}`, exec_options);
var filename = msg.filepath.replace(/^.*[\\\/]/, '');
filename = __dirname + "\\json\\" + filename.substring(0, filename.length-3) + "json";
try{
const fs = require('fs');
const data = fs.readFileSync(filename, 'utf8');
processSharedStashQueries(JSON.parse(data), msg.username);
} catch(err) {
console.error(err);
}
process.exit();
}
});
const processSharedStashQueries = (data, username) => {
const INSERT_USER_QUERY = `insert into sharedstashes (NumStashes, SharedGold, NumItems, UserID) values (${data.numStashes}, ${data.sharedGold}, ${data.numItems}, (select id from users where username = '${username}'))`;
doQuery(INSERT_USER_QUERY);
};
When the child calls doQuery() inside processSharedStashQueries() the pool object will be logged and I can verify it is a valid and defined object and is the same exact pool object the parent process uses. However, nothing happens when the child hits the pool.query() line of code. No error and no console logs. It's as if nothing happens.
Why can the child process "see" the pool object but not be able to use it?
Is my overall approach incorrect? I fear I might be missing some knowledge in how to use npm mysql effectively to do such a thing. Should I put the MySQL query smarts inside the external java program? Or is that bad design?
Thanks in advance!

Best way to structure a mysql+nodejs+express app

I use mysql (without sequelize) and generally create the connection in a module.export function which I then require from other files like so:
var db;
module.exports={
getConnection = function (){return new Promise(function(resolve, reject){
// db = mysql connection stuff
resolve(db)
});},
//other database related operations similarly
}
Now, I want to separate everything for example, I want to have a userModel that will have a few database operations related to users which will just import the db connection and so on;
But what is the optimal way of achieving this? Thanks.
Since it's used so broadly and doesn't present a high risk of variable naming conflict, I prefer to add it to the global object. Then you never have to make sure it's being included, passed, or imported from a module.
Consider the following example:
// in your application initialization file such as app.js
// require items …
const mysql = require('mysql');
const connection = mysql.createPool({
connectionLimit: 10,
host: process.env.DB_HOST || '127.0.0.1',
user: process.env.DB_USER || 'local_user',
password: process.env.DB_PASSWORD || 'local_password',
database: process.env.DB_NAME || 'local_database',
multipleStatements: true,
charset: 'utf8mb4' // necessary if you might need support for emoji characters
});
connection.on('connection', function (connection) {
// handy for testing
console.log('Pool id %d connected', connection.threadId);
});
connection.on('enqueue', function () {
// handy for testing
console.log('Waiting for available connection slot');
});
// make the connection global via the the variable db
global.db = connection;
// everywhere else in your app, use the now global db variable when running queries
db.query(
'INSERT INTO users SET ?', [{name: "John Smith"}], function(error, results, fields) {
if (error) throw error;
console.log(results);
});
}

Express - Multiple database connections

I'm developing an application with node.js and in login form I ask user to select the database but I don't know how to set the connection with the selected database.
How can I put several connections in my config.js?
And how can I set a connection wit a selected database?
var mssql = require("mssql");
var config =
{
user: "user",
password: "password",
server: "IP",
database: "db_name"
}
var db = new mssql.Connection(config);
db.connect(function(err)
{
console.log(err);
});
module.exports = db;
Thank you
To do this, you can just make two database connections
var mssql = require("mssql");
var config =
{
user: "user",
password: "password",
server: "IP",
database: "db_name"
}
var db = new mssql.Connection(config);
var db2 = new mssql.Connection(config);
db.connect(function(err)
{
console.log(err);
});
db2.connect(function(err)
{
console.log(err);
});
module.exports = {db: db, db2: db2};
If you need a separate config, you can just make two configs. To use the first db, just require("config").db and the second db is at require("config").db2

How to get Data from MongoDb using mongoose?

I just started learning MongoDB and mongoose. Currently I have the following structure:
database -> skeletonDatabase
collection -> adminLogin
When I run db.adminLogin.find() from the command line I get:
{ "_id" : ObjectId("52lhafkjasfadsfea"), "username" : "xxxx", "password" : "xxxx" }
My connection (this works, just adding it FYI)
module.exports = function(mongoose)
{
mongoose.connect('mongodb://localhost/skeletonDatabase');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
console.log('Conntected To Mongo Database');
});
}
My -js-
module.exports = function(mongoose)
{
var Schema = mongoose.Schema;
// login schema
var adminLogin = new Schema({
username: String,
password: String
});
var adminLoginModel = mongoose.model('adminLogin', adminLogin);
var adminLogin = mongoose.model("adminLogin");
adminLogin.find({}, function(err, data){
console.log(">>>> " + data );
});
}
My console.log() returns as >>>>
So what am I doing wrong here? Why do I not get any data in my console log? Thanks in advance for any help.
mongoose by default takes singular model names and pairs them with a collection named with the plural of that, so mongoose is looking in the db for a collection called "adminLogins" which doesn't exist. You can specify your collection name as the 2nd argument when defining your schema:
var adminLogin = new Schema({
username: String,
password: String
}, {collection: 'adminLogin'});
Had a problem with injecting it within an express route for my api so I changed it thanks to #elkhrz by first defining the schema and then compiling that one model I want to then pull like so:
app.get('/lists/stored-api', (req, res) => {
Apis.find(function(err, apis) {
if (err) return console.error(err);
res.send(apis);
});
});
I wouldn't send it to the body, I would actually do something else with it especially if you plan on making your API a production based application.
Run through this problem and read up on possible proper ways of rendering your data:
How to Pass Data Between Routes in Express
Always a good idea to practice safe procedures when handling data.
first compile just one model with the schema as an argument
var adminLogin = mongoose.model('adminLogin', adminLogin);
in your code adminLogin does not exist, adminLoginModel does;
after that ,instead to
adminLogin.find({}, function(err, data){
console.log(">>>> " + data );
});
try this
adminLogin.find(function (err, adminLogins) {
if (err) return console.error(err);
console.log(adminLogins);
is important the "s" because mongo use the plural of the model to name the collection, sorry for my english...

Why mongodb find() never got to my callback

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.

Categories

Resources