Updating an object attribute from a method - javascript

I'm trying to understand why the following code doesn't work. Basically, I want to handle the database connection in a Node module, while using the same database connection.
Here's my module:
var MongoClient = require("mongodb").MongoClient;
var url = "mongodb://localhost:27017";
module.exports = {
resource: null,
connect: function() {
MongoClient.connect(
url,
function(err, db) {
if (err) throw err;
console.log("Connected!");
this.resource = db; // Updating the object's attribute
}
);
},
};
And my main file:
var db = require('./db.js');
db.connect(); // Outputs "connected!"
http.createServer(function (req, res) {
console.log(db.resource) // Outputs "null"
}).listen(8080);
The resource attribute is never updated. I suspect a scope issue but I don't know how to address it.

The use of function() to define both exports.connect and the callback to MongoClient.connect causes the this ("context") binding on the function body to change to the function itself. To avoid this behaviour, use ES6' Arrow Function syntax, which does not change the context bindings:
var MongoClient = require("mongodb").MongoClient;
var url = "mongodb://localhost:27017";
module.exports = {
resource: null,
connect: () => {
MongoClient.connect(
url,
(err, db) => {
if (err) throw err;
console.log("Connected!");
this.resource = db; // Updating the object's attribute
}
);
},
};
Or you may move the connect definition outside of the object, and assign exports.resource through the use of a full object path, as so:
var MongoClient = require("mongodb").MongoClient;
var url = "mongodb://localhost:27017";
module.exports = {
resource: null,
connect: undefined
},
};
module.exports.connect = function() {
MongoClient.connect(
url,
function(err, db) {
if (err) throw err;
console.log("Connected!");
module.exports.resource = db; // Updating the object's attribute
}
);
};

Related

Node JS : use mongodb on imported module

I have a app.js that connect to a mongodb database an display it with express.My app.js is starting to be quite long. So I'm trying to do "modular design". I need to do a "timer.js" that will do some stuff in my mongodb with a timer.
I want to import this function from "checking.js" but this file require mongodb, some constant from DOTENV etc. so I need a import/export relation between them. How to do it ?
App.js (main file)
require('dotenv').config()
const POWER = process.env.POWER;
var mongoDb = require('mongodb');
var mongoClient = mongoDb.MongoClient;
const serverUrl = process.env.ENV_SERVEUR_MONGO_URL;
const useDB = process.env.ENV_MONGO_DATABASE;
app.get('/top', function (req, res) {
var resultArray = [];
mongoClient.connect(serverUrl, function (err, client) {
var db = client.db(useDB);
if (err) throw err;
var cursor = db.collection('top').find().sort({ _id: -1 });
cursor.forEach(function (doc, err) {
resultArray.push(doc);
}, function () {
client.close();
res.render('pages/top', { items: resultArray })
});
});
});
var checking = require('./checking')
Checking.js
function checkingdatabase() {
// ERROR require mongodb, variable undefined etc.
mongoClient.connect(serverUrl, function (err, client) {
var db = client.db(useDB);
if (err) throw err;
//do stuff
});
}
setInterval(checkingActiveOffer, 5000);
module.exports = Object.assign({ checkingdatabase })```
create DB.js file and share MongoDB connection
mongoose.connect(process.env.ENV_SERVEUR_MONGO_URL;, { useFindAndModify: false, useUnifiedTopology: true, useNewUrlParser: true })
.then(function (res) {
console.log('Succeeded connected to: ' + process.env.ENV_SERVEUR_MONGO_URL;);
exports.isReady = true;
exports.connection = res;
exports.con = res.connection
})
Checking.js
var db = require('./DB')
app.get('/top', function (req, res) {
db.con.collection('top').find().sort({_id:-1}).toArray()
.then(r=>{
res.render('pages/top', { items: resultArray })
})
})
You can do it in two different ways:
1 - You pass the values you need as a prop to Checking function. So this way you would pass your envs and your mongo client when you invoke Checking function. Not advisable
2 - You can, and should, declare the things you need inside the Checking file. Your envs and mongoClient can just be required there, and it will make your code cleaner.
Take a look at this code and see if that suits your use case.

Passing variable from one js to another js file in nodejs

I'm just getting started with Nodejs, so please bear with me
I store my DB setting on the first JS, connect.js :
var mysql = require('mysql');
module.exports = function(connectDB) {
var connectDB = {};
connectDB.connection = mysql.createConnection({
//db params
});
connectDB.connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
return connectDB;
};
Then I stored my query in another JS file, lets call it dbManager.js :
var db = require('./connect')(connectDB);
var test_connection = connectDB.connection.query('SELECT * FROM `test`', function (error, results, fields) {
console.log(results);
});
exports.test = test_connection;
My goal is to pass the connection variable from connect.js to dbManager.js, so I could use it for running some queries.
The above code return an error, which said the variable is not passed successfully to dbManager.js :
ReferenceError: connectDB is not defined
Thanks in advance
The syntax error is because you cant define variables within an object literal using var.
e.g., you can't do the following,
var t = {
"r": 4,
var g = 5;
};
You can do this,
var t = {
"r": 4,
"g" : 5
};
And to access the properties of the object you can do,
console.log(t["r"]);
console.log(t.g);
In your code the problem is declaring a variable inside an object literal. Yo could do,
var connectDB = {};
connectDB.connection = mysql.createConnection({
//DB params
});
connectDB.connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connectDB.connection.threadId);
});
return connectDB;
Edit1 As per OP's comments,
connect.js:-
Changes- No need of the connectDB param, using module.exports functionality.
var mysql = require('mysql');
var connectDB = {};
connectDB.connection = mysql.createConnection({
//db params
});
connectDB.connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connectDB.connection.threadId);
});
module.exports = connectDB;
dbManager.js:-
var db = require('./connect');//removed the parameter
//use db variable to process queries as returned from the above require statement.
var test_connection = db.connection.query('SELECT * FROM `test`', function (error, results, fields) {
console.log(results);
});
exports.test = test_connection;
**you can do it like this
connection.js**
var mysql=require('mysql');
// Database Connection
var connection = mysql.createConnection({
host : hostname,
user :username,
password : password,
database : databasename,
multipleStatements:true
});
try {
connection.connect();
} catch(e) {
console.log('Database Connetion failed:' + e);
}
module.exports=connection;
**you can use this connection file in your dbmanager file like
this..**
var db = require('./connection.js');var test_connection =
connection.query('SELECT * FROM test', function(err,result) {
console.log(result);
});
Will something like this work for you? You can have a file that returns a connection object from the pool:
var mysql = require('mysql');
module.exports = function() {
var dbConfig = {...};
var database = mysql.createPool(dbConfig);
return {
getConnection: function(callback) {
// callback(error, connection)
database.getConnection(callback);
}
};
};
Wherever you need to use it, you can require it as follows:
var connector = require('./db-connector')();
Then use it like this:
connector.getConnection(function(error, connection) {
// Some code...
// Be sure to release the connection once you're done
connection.release();
});
This is how I store config data to pass around on my node server. I call it config.js and .gitignore it. I keep a sample copy called config.sample.js
let config = {};
config.mysql-host='localhost' || process.env.MYSQL_HOST;
config.mysql-user='me' || process.env.MYSQL_USER;
config.mysql-secret='secret' || process.env.MYSQL_SECRET;
config.mysql-database='my_db' || process.env.MYSQL_DB;
module.exports = config; //important you don't have access to config without this line.
To use it I would do the following.
const config = require('./config');
const mysql = require('mysql');
const connection = mysql.createConnection({
host: config.host,
user: config.user,
password: config.password,
});
connection.connect((err) => {
if(err) {
console.error(`error connecting: ${err.stack});
return;
}
console.log(`connected`);
});
const test_connection = connectDB.connection.query('SELECT * FROM `test`'(error, results, fields) => {
console.log(results);
});

Node.js Module class returns undefined

This is my database class which I want to exist only once because I want only one connection for the application and not multiple connections.
var mysql = require('mysql');
var fs = require("fs");
var eventEmitter = require("./events.js");
function Database() {
this.connection;
this.poolCluster;
var host;
var username;
var password;
var db;
var config;
var clusterConfig = {
removeNodeErrorCount: 5,
restoreNodeTimeout: 1000,
defaultSelector: 'ORDER'
};
var poolConfig = {
acquireTimeout: 10000,
waitForConnections: false,
connectionLimit: 10,
queueLimit: 0
};
this.connect = function() {
this.connection = mysql.createConnection({
host: config.mysqlHost,
user: config.mysqlUsername,
password: config.mysqlPassword,
database: config.mysqlDb
});
this.connection.connect(function(err) {
if(err) {
console.error("Connection couldn't established at " + config.mysqlHost + " (user: " + config.mysqlUsername + ")"
+ "\nError: " + err);
return;
}
console.log("Connected to mysql server at " + config.mysqlHost + " (user: " + config.mysqlUsername + ")");
this.poolCluster = mysql.createPoolCluster(clusterConfig);
this.poolCluster.add("APP", poolConfig);
this.poolCluster.add("ACCOUNTS", poolConfig);
this.poolCluster.add("GAME", poolConfig);
console.log("Created Connection Clusters\n- APP\n- ACCOUNTs \n- GAME");
eventEmitter.emit("MysqlConnectionReady");
});
};
this.getMainConnection = function() {
return this.connection;
};
this.getAppConnection = function() {
this.poolCluster.getConnection("APP", 'ORDER', function(err, connection) {
if(err) throw err;
return connection;
});
};
this.getAccountsConnection = function() {
this.poolCluster.getConnection("ACCOUNTS", 'ORDER', function(err, connection) {
if(err) throw err;
return connection;
});
};
this.getGameConnection = function() {
this.poolCluster.getConnection("GAME", 'ORDER', function(err, connection) {
if(err) throw err;
return connection;
});
};
fs.readFile(process.cwd() + "/config.json", 'utf8', function(err, data) {
if(err) throw err;
config = JSON.parse(data);
this.connect();
});
}
module.exports = Database:
In my code I set module.exports = Database;
When I want to use Database in another file its undefined. I want to use this in another file and I want to use only instance of that because I want only one connection for the app Im running.
But if I use require('./Database.js'j; and use the var it returns undefined
To use the pseudo-classical OOP approach, where you define a Class as a JS function (as shown in your snippet), you would instantiate an object with the new keyword.
Instead of module.exports = Database, try creating the instance and exporting that as the module, like this:
const db = new Database();
module.exports = db

What is wrong with my database file?

this is my database.js file:
const MongoClient = require('mongodb').MongoClient;
const db = function(){
return MongoClient.connect('mongodb://localhost:27017/users', (err, database) => {
if (err) return console.log(err);
return database;
});
}
module.exports = db;
I icluded it to my server.js like this:
var db = require('./database');
but when I want to use it like this
db().collection('orders')
I am getting a TypeError (Cannot read property 'collection' of undefined)
Edit: sorry, I made an issue during writing this question of course I used db().collection
The issue is with your export, and misunderstood behavior of node's callbacks.
const MongoClient = require('mongodb').MongoClient;
const db = function(){
return MongoClient.connect('mongodb://localhost:27017/users', (err, database) => {
// this is inside a callback, you cannot use the database object outside this scope
if (err) return console.log(err);
return database; // this database object is what you should be exporting
});
}
module.exports = db; // You are exporting the wrong variable
One way to fix this is (may not be the best) to export the database object that we receive in the callback. Example:
const MongoClient = require('mongodb').MongoClient;
let database = null;
MongoClient.connect('mongodb://localhost:27017/users', (err, db) => {
if (err) return console.log(err);
database = db;
});
module.exports = database;
And now you can use the db, but with a null check.
var db = require('./database');
if (db !== null) {
db.collection('orders').find({}, (err, docs) => {
if (err) return console.log(err);
console.log(docs);
});
}
But this may lead to connection being established again and again when you require the database.js file (I am not sure about this). A better approach would be:
const MongoClient = require('mongodb').MongoClient;
let database = null;
const connect = () => {
if (database !== null) return Promise.resolve(database);
return new Promise((resolve, reject) => {
MongoClient.connect('mongodb://localhost:27017/users', (err, db) => {
if (err) return reject(err);
database = db;
resolve(database);
});
});
};
module.exports = connect;
and then use it like:
var dbConnect = require('./database');
dbConnect().then((db) => {
db.collection('orders').find({}, (err, docs) => {
if (err) return console.log(err);
console.log(docs);
});
}).catch((err) => {
console.error(err);
});

In a Node web app, do you open one MongoDB connection for each HTTP request?

I'm adding MongoDB to my Express.js Node web app. This is what I got so far:
// in app.js
var mongodb = require('mongodb');
var mongourl = /* … */;
// These are just examples:
app.get('/write', function (req, res) {
mongodb.connect(mongourl, function (err, db) {
db.collection('Users', function (err, coll) {
coll.insert(/* stuff */, function (err) {
res.send(200, 'Done.');
});
});
});
});
app.get('/read', function (req, res) {
mongodb.connect(mongourl, function (err, db) {
db.collection('Users', function (err, coll) {
coll.find({}, function (err, cursor) {
cursor.toArray(function (err, items) {
res.send(200, items);
});
});
});
});
});
Assuming that I want to stick with the default mongodb driver (for now):
Is this pattern right? Do I have to open a new connection to the database in each of my different routes that perform database operations?
If the pattern is right, then how do I deal with the obvious code repetition going on here? Obviously, as it stands now, the code is not acceptable.
Use the new standard, MongoClient. It manages the pool for you, defaults to 5.
//require as a module to be used anywhere.
module.exports = {}
var MongoClient = require('mongodb').MongoClient;
var mongoURI = /* … */;
MongoClient.connect(mongoURI, function(err, db) {
if(err) throw err;
module.exports.users = db.collection('users');
console.log('Connected to Mongo!')
})
then
var db = require('./db.js')
//once connected
//db.users.find()... etc
check out:
http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html
pooling details:
http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#connection-pool-configuration
Do not close and reopen connection, you're just loosing resources :s

Categories