I am having trouble understanding node.js.
Example, MongoDB access, here's what I've got (mydb.js):
var mongodb = require('mongodb'),
server = new mongodb.Server('staff.mongohq.com', 10030, {
auto_reconnect: true
}),
db = new mongodb.Db('mydb', server);
function authenticateAndGo(db, handle) {
db.authenticate('username', 'password', function(err) {
if (err) {
console.log(err);
return;
}
console.log('Database user authenticated');
var collection = new mongodb.Collection(db, 'test');
handle(collection);
});
}
function query(handle) {
db.open(function(err, db) {
if( err ) {
console.log(err);
return;
}
console.log('Database connected');
authenticateAndGo(db, handle);
});
};
exports.query = query;
So, if I want to use it later, I would
var mydb = require('./mydb');
mydb.query(function(collection) {
collection.find({}, {
limit: 10
}).toArray(function(err, docs) {
console.log(docs);
});
});
But, If I do multiple calls, like so:
var mydb = require('./mydb');
mydb.query(function(collection) {
collection.find({}, {
limit: 10
}).toArray(function(err, docs) {
console.log(docs);
});
});
mydb.query(function(collection) {
collection.find({}, {
limit: 10
}).toArray(function(err, docs) {
console.log(docs);
});
});
I get an exception:
Error: db object already connecting, open cannot be called multiple times
I think that there is really something fundamental that I do not understand about all this and it is probable that this question is stupid ...
Anyway, all help is welcome.
Thanks in advance.
mydb.js:
var mongodb= require('mongodb'),
server = new mongodb.Server('staff.mongohq.com', 10030, {
auto_reconnect: true
}),
db1 = new mongodb.Db('mydb', server);
// callback: (err, db)
function openDatabase(callback) {
db1.open(function(err, db) {
if (err)
return callback(err);
console.log('Database connected');
return callback(null, db);
});
}
// callback: (err, collection)
function authenticate(db, username, password, callback) {
db.authenticate(username, password, function(err, result) {
if (err) {
return callback (err);
}
if (result) {
var collection = new mongodb.Collection(db, 'test');
// always, ALWAYS return the error object as the first argument of a callback
return callback(null, collection);
} else {
return callback (new Error('authentication failed'));
}
});
}
exports.openDatabase = openDatabase;
exports.authenticate = authenticate;
use.js:
var mydb = require('./mydb');
// open the database once
mydb.openDatabase(function(err, db) {
if (err) {
console.log('ERROR CONNECTING TO DATABASE');
console.log(err);
process.exit(1);
}
// authenticate once after you opened the database. What's the point of
// authenticating on-demand (for each query)?
mydb.authenticate(db, 'usernsame', 'password', function(err, collection) {
if (err) {
console.log('ERROR AUTHENTICATING');
console.log(err);
process.exit(1);
}
// use the returned collection as many times as you like INSIDE THE CALLBACK
collection.find({}, {limit: 10})
.toArray(function(err, docs) {
console.log('\n------ 1 ------');
console.log(docs);
});
collection.find({}, {limit: 10})
.toArray(function(err, docs) {
console.log('\n------ 2 ------');
console.log(docs);
});
});
});
Result:
on success:
Database connected
Database user authenticated
------ 1 ------
[ { _id: 4f86889079a120bf04e48550, asd: 'asd' } ]
------ 2 ------
[ { _id: 4f86889079a120bf04e48550, asd: 'asd' } ]
on failure:
Database connected
{ [MongoError: auth fails] name: 'MongoError', errmsg: 'auth fails', ok: 0 }
[Original Answer]:
You're opening the db multiple times (once in each query). You should open the database just once, and use the db object in the callback for later use.
You're using the same variable name multiple times, and that might've caused some confusion.
var mongodb = require('mongodb'),
server = new mongodb.Server('staff.mongohq.com', 10030, {
auto_reconnect: true
}),
db1 = new mongodb.Db('mydb', server);
function authenticateAndGo(db, handle) {
db.authenticate('username', 'password', function(err) {
if (err) {
console.log(err);
return;
}
console.log('Database user authenticated');
var collection = new mongodb.Collection(db, 'test');
handle(collection);
});
}
function query(handle) {
db1.open(function(err, db2) {
if( err ) {
console.log(err);
return;
}
console.log('Database connected');
authenticateAndGo(db2, handle);
});
};
exports.query = query;
I've changed the above code a little (db1 for the original db, db2 for the opened db). As you can see, you're opening db1 multiple times, which is not good. extract the code for opening into another method and use it ONCE and use the db2 instance for all your queries/updates/removes/...
You can only call "open" once. When the open callback fires, you can then do your queries on the DB object it returns. So one way to handle this is to queue up the requests until the open completes.
e.g MyMongo.js
var mongodb = require('mongodb');
function MyMongo(host, port, dbname) {
this.host = host;
this.port = port;
this.dbname = dbname;
this.server = new mongodb.Server(
'localhost',
9000,
{auto_reconnect: true});
this.db_connector = new mongodb.Db(this.dbname, this.server);
var self = this;
this.db = undefined;
this.queue = [];
this.db_connector.open(function(err, db) {
if( err ) {
console.log(err);
return;
}
self.db = db;
for (var i = 0; i < self.queue.length; i++) {
var collection = new mongodb.Collection(
self.db, self.queue[i].cn);
self.queue[i].cb(collection);
}
self.queue = [];
});
}
exports.MyMongo = MyMongo;
MyMongo.prototype.query = function(collectionName, callback) {
if (this.db != undefined) {
var collection = new mongodb.Collection(this.db, collectionName);
callback(collection);
return;
}
this.queue.push({ "cn" : collectionName, "cb" : callback});
}
and then a sample use:
var MyMongo = require('./MyMongo.js').MyMongo;
var db = new MyMongo('localhost', 9000, 'db1');
var COL = 'col';
db.query(COL, function(collection) {
collection.find({}, {
limit: 10
}).toArray(function(err, docs) {
console.log("First:\n", docs);
});
});
db.query(COL, function(collection) {
collection.find({}, {
limit: 10
}).toArray(function(err, docs) {
console.log("\nSecond:\n", docs);
});
});
I simply call the open function once directly after the db init:
var mongodb = require('mongodb');
var server = new mongodb.Server('foo', 3000, {auto_reconnect: true});
var db = new mongodb.Db('mydb', server);
db.open(function(){});
After that I do not have to care about that anymore because of auto_reconnect is true.
db.collection('bar', function(err, collection) { [...] };
Related
So I have done C++ Java and PHP and wanted to give a crack at Node.js. Below I have a very simple and unsecured SQL query.
module.exports = {
LoginCheck: function(data,cb){
console.log(data.password);
console.log(data.username);
if(data.username && data.password){
console.log('we have arrived');
var config = require(__dirname+'/../Config/config.json');
var mysql = require('mysql');
var con = mysql.createConnection({
host: config.LoginDBhost,
port: config.LoginDBport,
user: config.LoginDBusername,
password: config.LoginDBpassword,
database: config.LoginDB
});
con.connect(function(err) {
if (err) throw err;
console.log('we have connected');
con.query("SELECT * FROM `Users` WHERE `Username` = '"+data.username+"'", function (err, result) {
if (err) console.log(err);
if(result.Password){
if(result[0].Password){
if(result[0].Password == data.password){
console.log('true');
cb(true);
}
}
}
});
});
}
//either password is null or didnt match on file... if we are this far its a fail
console.log('false');
cb(false);
},
bar: function () {
// whateverss
}
};
The code does not wait for the sql connection and skips to being false. I been banging my head on a desk for days trying to figure out how promises and callbacks works after years of having my code follow steps layed.
Could someone convert this and explain how to force my code to be synchronous when I need it to be?
Try this code :
module.exports = {
LoginCheck: function(data,cb){
console.log(data.password);
console.log(data.username);
if(data.username && data.password){
console.log('we have arrived');
var config = require(__dirname+'/../Config/config.json');
var mysql = require('mysql');
var con = mysql.createConnection({
host: config.LoginDBhost,
port: config.LoginDBport,
user: config.LoginDBusername,
password: config.LoginDBpassword,
database: config.LoginDB
});
con.connect(function(err) {
// I think cb(false) here but you use throw err.
if (err) throw err;
console.log('we have connected');
con.query("SELECT * FROM `Users` WHERE `Username` = '"+data.username+"'", function (err, result) {
if (err) console.log(err);
if(result.Password){
if(result[0].Password){
if(result[0].Password == data.password){
console.log('true');
cb(true);
}
}
}
//either password is null or didn't match on file... if we are this far its a fail
console.log('false');
cb(false);
});
});
}
},
bar: function () {
// whateverss
}
};
I'm trying to build a chatbot using Botpress. I'm a beginner, looking for your help. One of the requirements is to query database to answer questions. This is what I have tried so far:
dbconnect.js
var oracledb = require('oracledb');
var dbConfig = require('./dbconfig.js');
var db = function dbCall(sql, values) {
return new Promise(function(resolve, reject){
oracledb.getConnection(
{
user : dbConfig.user,
password : dbConfig.password,
connectString : dbConfig.connectString
},
function(err, connection) {
if (err) {
reject(err);
return;
}
connection.execute(
sql,
values,
{
maxRows: 1
},
function(err, result) {
if (err) {
console.error(err.message);
return;
}
resolve(result);
doRelease(connection);
}
);
});
});
}
// Note: connections should always be released when not needed
function doRelease(connection) {
connection.close(
function (err) {
if (err) {
console.error(err.message);
}
});
}
module.exports = db;
select.js
var dbConnect = require('../oracledb/dbconnect');
dbConnect('select code from table1' +
' where id=:id', {id:'value1'}).then(function (response) {
console.info(response.rows);
}).catch(function(error) {
console.info(error);
});
everything above works great, if I run select.js. How could I bring the response into the botpress chat window? I tried placing the select.js code in index.js event.reply, it doesn't work.
Thanks,
Babu.
I have resolved this by using the promise directly in the action.
return dbConnect('<SQL here>=:id', { id: Id })
.then(function(response) {
var res = response.rows
console.info(res);
const newState = { ...state, status: res}
return newState
})
.catch(function(error) {
console.info(error)
})
Note that response has the resultset.
I am trying to connect to mongodb from node and I am getting below error
node_modules\mongodb\lib\mongo_client.js:458
throw err
^
ReferenceError: connect is not defined
I am using the mongodb module version
2.0.48
I am trying to run a simple test code
(function (dbase) {
var mdb = require('mongodb');
var mongoUrl = "mongodb://localhost:27017/theBoard";
var connection;
dbase.dbConnection = function (next) {
if (connection) {
next(null, connection);
} else {
mdb.MongoClient.connect(mongoUrl, function(err, db) {
if (err) {
next(err, null);
} else {
console.log("connected");
connection = { db: db , notes: db.collection("notes")};
next(null, connection);
}
});
}
}
Can someone please help me understand this issue.
---Additional information
data module -
(function (data) {
var mdb = require('./db.js');
data.GetCategory = function() {
mdb.dbConnection(function(err, db) {
if (err)
console.log("Error connecting to mango");
if (connect) {
db.notes.count(function(err, count) {
if (err)
console.log("Failed to retreive collection");
else
console.log("Count - "+count);
});
console.log("Connected");
}
});
}})(module.exports);
db.js
(function (dbase) {
var mdb = require('mongodb');
var mongoUrl = "mongodb://localhost:27017/theBoard";
var connection;
dbase.dbConnection = function (next) {
if (connection) {
next(null, connection);
} else {
mdb.MongoClient.connect(mongoUrl, function(err, db) {
if (err) {
next(err, null);
} else {
console.log("connected");
connection = { db: db , notes: db.collection("notes") };
next(null, connection);
}
});
}
} })(module.exports);
Controller -
(function (controller) {
var data = require('.././data');
controller.init = function (app) {
app.get("/", handleRequest);
}
var handleRequest = function (req, res) {
data.GetCategory();
var a = {};
a.send = "Mamma is coming home";
res.send(a);
}
})(module.exports);
Just in case some one runs into an issue like this due to bad coding practice even if it for test purpose is to never have function names which are the same as the function names in the API. In db.js I had an undefined variable named connect which trowing and error when it was accessed and since it was called through the API function called "connect" the error was thrown by the API leading me to believe that the API function had an issue
here is my model code to insert some records. On my work pc it works perfectly, but when I'm running it on my home pc with the same OS, collection.insert doesn't running its callback, so I get just long request which ends with time out. There are no errors, mongo db logs say "Connection accepted" 5 times, and after that there are no messages. The same happens when I try to fetch objects from database using find(). Inserting records with mongo shell works great, but with node.js I couldn't accomplish that.
/*
* POST populate locations.
*/
var MongoClient = require('mongodb').MongoClient,
_ = require('underscore'),
env = process.env.NODE_ENV || 'development',
config = require('../config/config')[env]
exports.connect = function(cb) {
MongoClient.connect(config.db, function(err, db) {
if (err) throw err;
cb(db)
});
}
exports.populate = function(data, cb) {
var self = this;
self.connect(function(db) {
var collection = db.collection('locations');
collection.insert(data, function(err, docs) {
collection.ensureIndex({
"loc": "2dsphere"
}, function() {
db.close();
cb();
});
});
});
}
Use
exports.populate = function(data, cb) {
MongoClient.connect(config.db, function(db) {
var collection = db.collection('locations');
collection.insert(data, function(err, docs) {
collection.ensureIndex({
"loc": "2dsphere"
}, function() {
db.close();
cb();
});
});
});
}
I am using node.js with socket.io to push real time notifications to users. However, currently I am just sending back a query result done in my socket.io code and sending it back to the client but I need to let socket know about the changes that occur and to either update with the changes or re-query the db to check for the new number and send that to the client.
For example if a user gets a friend request then the notification count will change and I want socket.io to push the new notification count number to the user.
here is my socket.io code in my app.js file:
io.on('connection', function(socket) {
var sessionID = socket.handshake.sessionID,
session = new connect.middleware.session.Session({ sessionStore: sessionStore }, socket.handshake.session)
console.log('socket: new ' + sessionID)
socket.broadcast.emit('arpNewConn', session.passport.user)
var intervalID = setInterval(function() {
socket.handshake.session.reload(function() {
socket.handshake.session.touch().save()
})
socket.emit('pulse', { heartbeat: new Date().toString(), timestamp: new Date().getTime() })
}, 300 * 1000)
socket.on('disconnect', function() {
console.log('socket: dump ' + sessionID)
socket.broadcast.emit('arpLostConn', session.passport.user)
clearInterval(intervalID)
})
socket.emit('entrance', {message: 'Message works'});
dbnotif.findOne(userID, function (err, user) {
if(err) throw err;
notify = user.notifications;
socket.emit('notify', {notific: notify});
});
});
Here is the client side:
div#CheckSocket
script(src='http://localhost:3000/socket.io/socket.io.js')
script.
$(document).ready(function () {
console.log('socket');
var socket = io.connect('http://localhost:3000/');
console.log('entered1');
socket.on('entrance', function (data) {
console.log('entered');
console.log(data.message);
});
socket.on('notify', function (data) {
console.log('noting');
console.log(data.notific);
if(data.notific !== 0)
$('.notifications').html(data.notific);
});
socket.on('reconnecting', function(data) {
setStatus('reconnecting');
console.log('entered2');
});
function setStatus(msg) {
console.log('connection status: ' + msg);
console.log('entered5');
}
});
Here is the example of adding a friend in the route file:
exports.addContactPost = function(req, res, err) {
async.waterfall([
function(callback) {
var success;
var newFriend = new Friend ({
userId: req.signedCookies.userid,
friend_id: mongoose.Types.ObjectId(req.body.otherUser),
friend_status: 1
});
newFriend.save(function(err){
if(err) {
console.log(err);
} else {
console.log("saved it");
success = true;
}
});
callback(null, success)
},
function(success, callback) {
//if(success === true) {
var success2;
var newFriend2 = new Friend ({
userId: mongoose.Types.ObjectId(req.body.otherUser),
friend_id: req.signedCookies.userid,
friend_status: 2
});
newFriend2.save(function(err){
if(err) {
res.send("request not received");
} else {
success2 = true;
}
});
callback(null, success2);
//} else {
// res.send("error with request sent");
//}
},
function(success2, callback) {
console.log('callback3');
//if(success2 === true) {
var success3;
Notification.findOneAndUpdate({userId: mongoose.Types.ObjectId(req.body.otherUser)}, {
$inc: {notifications: 1}
}, function(err, notify) {
if(err) {
res.send(err);
} else {
console.log(notify);
if(notify.added_notifications === true) {
// enable mail and include general u have got a new request... do not include name because not storing it
}
}
success3 = true;
callback(null, success3);
}],
function(err, results) {
res.json({response: true});
console.log("Add successful");
});
};
Notes: dbnotif is a model being called by mongoose,
userID is a global variable available to the file
I helped him solve this question offline, but we ended up using an EventEmitter as a proxy.
// main.js
var EventEmitter = require('events').EventEmitter;
var emitter = new EventEmitter();
Then add it to each request as middleware:
// elsewhere in main.js
app.use(function(req, res, next) {
req.emitter = emitter;
next();
});
Then in external routes file:
// routes.js
exports.addContactPost = function(req, res, err) {
req.emitter.emit( 'some-key', whatever, data, you, want );
};