I'm doing an application with Node.js, Express, MongoDB (mongoose), I'm trying to make the database connection in a separate file from server.js, but I'm having a hard time with connect-mongo.
First in my server.js I had this:
/* jshint esversion: 6 */
'use strict';
let express = require('express');
const db = require('./app/config/db');
const routes = require('./app/routes/routes');
const users = require('./app/routes/users');
let app = express();
const conn = db.connect();
app.set('views', path.join(__dirname, 'app/views'));
app.set('view engine', 'hbs');
...
app.use('/', routes);
app.use('/users', users);
app.listen(3000);
module.exports = app;
This only handle the application routes, and the application server, then I had the next folder structure for my project:
myApp
|___app
|___bin
|___config
|___credentials.js
|___db.js
|___controllers
|___routes
|___views
|___node_modules
|___package.json
|___server.js
Welll insidde config folder I had two javascripts that handle the connection to the database, in the credentials.js literally only had the credentials for the access of the database.
Then my problem is inside the db.js, next I show you the file:
/* jshint esversion: 6 */
'use strict';
let mongoose = require('mongoose'),
async = require('async'),
express = require('express');
const credentials = require('./credentials');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
let db = mongoose.connection,
app = express();
exports.connect = function(done){
const connection = mongoose.connect(credentials.host, credentials.database, credentials.port, credentials.db);
db.on('error', (error =>{
console.log("Error estableciendo la conexion");
process.exit(1);
}));
db.on('open', (argv)=>{
db.db.listCollections().toArray((err, collections)=>{
collections.forEach(x => console.log(x));
});
});
/* Define sessions in MongoDB */
app.use(session({
secret: credentials.sessionSecret,
store: new MongoStore({ dbPromise: db })
}));
}
I got the next error:
Error with nodemon server.js
Do you know how to initiate connect-mongo using this project structure?
By the way, in the credentials.js file I setup Bluebird as my promise library.
In advance thank you!
The problem was, like #MananVaghasiya said, that my variable db was not a Promise, this is a bug inside the mongoose project, so I changed the connection type to a basic uri connection with mongoose and then after the query of login I set the session.
The code it's looking like this at this time, so thank you for your time.
module.exports.login = (req, res)=>{
const mail = req.body.mail.replace(/^\s\s*/, '').replace(/\s\s*$/, ''),
password = req.body.password;
user.findOne({$and:[{'mail' : mail}, {'password': password}]}, (err, user)=>{
if(err){
res.send(err);
} else {
/* Define sessions in MongoDB */
app.use(session({
secret: credentials.sessionSecret,
store: new MongoStore({ mongooseConnection: db }),
saveUnitialized: true,
resave: false,
cookie:{
path: "/"
},
name: user.role
}));
return user;
}
});
};
Related
So I created a new node.js project and used express.js to build the basics to start of. Now I want to do a simple get call to get data from my database through a connection pool. When I do the call in app.js there is no problem, but when trying to do the same call from my users.js file in a get route it throws 'connection pool Cannot read properties of undefined (reading 'getConnection')'.
app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mysql = require('mysql');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// establish connection to database
var conpool = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: '****',
password: '****',
database: 'db_name'
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = {app, conpool};
user.js (located in routes directory which is on the same hierarchy level as app.js)
var express = require('express');
var router = express.Router();
var db = require('../app').conpool;
/* GET users listing. */
router.get('/get', function (req, res, next) {
db.getConnection((err, connection) => {
if (err) throw err;
var sql = null;
if (req.query.name) {
sql = 'SELECT * FROM users WHERE name = ' + sql.escape(req.query.name);
} else {
sql = 'SELECT * FROM users';
}
connection.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
});
});
});
module.exports = router;
Does anyone have any idea why this is happening? Is there something wrong with how I am using module.exports? Is it a problem of trying to call a function on a reference instead of the original pool object?
It seems Evert's solution was the one I was looking for. I'll describe the changes I made compared to the files shown in my question to show how it solved it.
I made a completely new file database.js (on the same level of hierarchy as app.js):
var mysql = require('mysql');
var conpool = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: '****',
password: '****',
database: 'db_name'
});
module.exports = conpool;
and deleted all these lines of code from app.js
in user.js only one line changed:
var db = require('../app.js')
to
var db = require('../database');
I have cloned a GitHub repo for reference. But i don't know what this .keys_dev refers to. Everything seems fine to me. But it is returning me error. Everything is in its place as expected. I hope anyone can help me. It requires stack that is unknown to me. It is requiring api that is already defined. I need to understand can anyone help?
const express = require("express");
const bodyPaser = require('body-parser');
const mongoose = require('mongoose');
const passport = require('passport');
const path = require('path');
const cors = require('cors');
const users = require('./routes/api/users');
const level = require('./routes/api/levels');
const employee = require('./routes/api/employees');
const exception = require('./routes/api/exception');
const payslip = require('./routes/api/payslip');
const dashboard = require('./routes/api/dashboard');
const individualcost = require('./routes/api/individualcost');
const oneoffpayment = require('./routes/api/oneoffpayment');
const record = require('./routes/api/record');
const app = express();
//Body parser middleware
app.use(bodyPaser.urlencoded({ extended: false }));
app.use(bodyPaser.json());
app.use(cors())
//Db
const db = require("./config/keys").mongoURI;
//MongoDB connection
mongoose
.connect(
db,
{ useNewUrlParser: true }
)
.then(() => console.log("MongoDB connected"))
.catch(err => console.log(err));
//Passport Middleware
app.use(passport.initialize());
//Passport config
require('./config/passport')(passport);
//Use routes
app.use('/api/users', users);
app.use('/api/level', level);
app.use('/api/employee', employee);
app.use('/api/exception', exception);
app.use('/api/payslip', payslip);
app.use('/api/dashboard', dashboard);
app.use('/api/individualcost', individualcost);
app.use('/api/oneoffpayment', oneoffpayment);
app.use('/api/record', record);
// Server static assets if in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`App is running on port ${PORT}`));
const db = require("./config/keys").mongoURI;
This require is fetching application configurations from the local filesystem, in this case the db URI. Perhaps the author of the repo forgot to mention that detail? It's very likely that if you want to use a MongoDB you'll have to setup your own local or cloud database and create a file under config/keys that contains a mongoURI. This should look similar to this:
// this is the contents of ./config/keys
export default {
mongoURI: "mongodb+srv://project:your-mongo-uri-here",
};
If you're looking to start a mongo cluster on the cloud, I've been using cloud.mongodb for a small pet project, works like a charm and it has a free plan tier.
You can also run mongo locally and just point the mongoURI to your local mongo instance.
I'm coding a session with NodeJS, when I get the user connection first create a session.client with the MAC ADDRESS, so far so good, but then I ask to the client if he want to continue and login on the app with social -network like Facebook, Instagram, Tweeter or Google+, and then when the user is redirected to the social login it back with other session from passportjs and clear al my init data of session and I lost the client information. So, I tried to change the name of the data in session, session.data, session.test, session.whatever but always happen the same, when I test and the passport redirect me and back to my domain, the session is clean and it change with new data from passportjs, any one know what's happen here? any idea how to solve this?
the code run perfectly, the problem is the session when go and back to // the social login, it clear my init data and back with the passport data. // I need my init data to continue working!
this is just an extract of code. It works
'use sctrict'
const https = require('https'),
fs = require('fs'),
path = require('path'),
morgan = require('morgan'),
logger = require('express-logger'),
express = require('express'),
favicon = require('serve-favicon'),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
passport = require('passport'),
// config files
port = 443,
mongodbConfig = require('./config/mongodb-config'),
session = require('express-session'),
keys = require('./config/keys'),
options = {
key: fs.readFileSync('./config/ssl/server.key'),
cert: fs.readFileSync('./config/ssl/server.crt')
},
cookieParser = require('cookie-parser'),
loginAPRoutes = require('./routes/loginAPRoutes'),
passportSetup = require('./config/passport-setup'),
app = express()
// MongoDB - Mongoose connection
const mongoose = require('mongoose')
mongoose.Promise - global.Promise
mongoose.connect('mongodb://' + mongodbConfig.mongodb.route + '/' + mongodbConfig.mongodb.db, {})
.then(() => console.log('db connected'))
.catch(err => console.log(err))
// config
app.set('view engine', 'ejs')
// middlewares
app.use(morgan('dev'))
app.use(favicon(path.join(__dirname, 'public/img/', 'favicon.ico')))
app.use(bodyParser.urlencoded({
extended: false
}))
app.use(bodyParser.json())
app.use(methodOverride('X-HTTP-Method-Override'))
app.use(express.static(path.join(__dirname, 'public')))
app.use(session({
secret: 'cybor-cat',
resave: false,
saveUninitialized: true
}))
// initilize passport
app.use(passport.initialize())
app.use(passport.session())
// Main routes
app.use('/guest', loginAPRoutes)
app.use('/auth', loginAPRoutes)
// Run the server https
https.createServer(options, app).listen(port, () => {
console.log('NodeJS Server Started... splice.pro is running!')
})
router.get('/s/:site', (req, res) => {
data = req.query
data.site = req.params.site
req.session.data = data
console.log('===== session ========')
console.log(req.session)
console.log('====== session END =======')
res.render('login')
})
/////////////// GOOGLE AUTH ////////////////
// route for google login
router.get('/google', passport.authenticate('google', {
scope: ['profile', 'email']
}))
// route for google and redirect
router.get('/google/callback',
passport.authenticate('google'), (req, res) => {
if (!req.user) {
res.redirect('/guest/s/site')
} else {
/////////// here comes the new session from passport :( //////
////////// and lost the first data of my session /////
console.log(req.session.data)
//////////////// this show the session with info of user ///////
/////////////// but req.session.data is lost ///////////
res.redirect('/guest/startconnection')
}
}
)
/////////////// GOOGLE AUTH END ////////////////
Well, well, well.... I found my problem, my external site redirect me to my server with the ip and when the request of passport login redirect , it back to the domain name, that's why it generate a new session id ... A long day but at the end I found it !
I am building a Node application using Express, Massive JS, and Postgresql. I was using sequelize but decided to try Massive JS, so I started converting my code to use it.
I have a login endpoint that I'm trying to reach from my Angular 5 app and I am getting an error. This error only occurs on my deployed application. It does work locally without any issues.
Here is the specific error:
TypeError: Cannot read property 'get_user' of undefined<br> at login (/root/firstImpression/server/features/auth/authController.js:7:26)
Here is my folder structure:
+Server
-server.js
+config
-secrets.js
+db
-get_user.sql
+features
+auth
-authController.js
-authRoutes.js
server.js file contents:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
const cookieParser = require('cookie-parser');
const secrets = require('./config/secrets');
const massive = require('massive');
// used to create, sign, and verify tokens
var jwt = require('jsonwebtoken');
// Parsers
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));
app.use(cookieParser());
//routes
require('./features/auth/authRoutes')(app);
//Connect to database
massive(secrets.development).then(db => {
app.set('db', db);
});
// Angular DIST output folder
app.use(express.static(path.join(__dirname, '../dist')));
//Set up static files
app.use(express.static('../dist'));
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../dist/index.html'));
});
//Set Port
const port = process.env.PORT || '3000';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`Running on localhost:${port}`));
get_user.sql file contents:
SELECT * FROM users WHERE username = $1;
authController.js file contents:
const jwt = require('jsonwebtoken');
const secrets = require('../../config/secrets');
const bcrypt = require('bcrypt');
module.exports = {
login: (req, res) => {
req.app.get('db').get_user(req.body.username).then(user => {
if(user[0]) {
bcrypt.compare(req.body.password, user[0].password,
function(err, result) {
if(result) {
var token = jwt.sign({user}, secrets.tokenSecret,
{expiresIn: '1h'});
res.status(200).json({
token: token,
user: user
})
} else {
res.status(200).json("Invalid username and/or
password.");
}
});
} else {
res.status(200).json("Could not find that user.");
}
})
}
}
authRoutes.js file contents:
var authController = require('./authController');
module.exports = (app) => {
app.post('/user-auth', authController.login);
}
The error is occuring in the authController.js file on this line:
req.app.get('db').get_user(req.body.username)
I've been reading the docs for massive js and learned the importance of keeping the DB folder on the same level where it's initialized, which is my server.js file.
As I stated earlier, when I run this on my local machine, it works great; However as soon as I deploy it to my live environment, I receive the error.
Any help or direction would be greatly appreciated. Let me know if any other information is required, and I will gladly provide it.
Your app setup should probably be wrap like
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
const cookieParser = require('cookie-parser');
const secrets = require('./config/secrets');
const massive = require('massive');
// used to create, sign, and verify tokens
var jwt = require('jsonwebtoken');
//Connect to database
massive(secrets.development).then(db => {
// Parsers
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));
app.use(cookieParser());
app.set('db', db);
// Angular DIST output folder
app.use(express.static(path.join(__dirname, '../dist')));
//routes
require('./features/auth/authRoutes')(app);
//Set up static files
app.use(express.static('../dist'));
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../dist/index.html'));
});
//Set Port
const port = process.env.PORT || '3000';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`Running on localhost:${port}`));
});
I am trying to run a query in a view (.ejs file). However, since the keyword require is not defined in a .ejs file, I need to export it from my main file, server.js.
The whole code for my server.js file is below and this is the specific snippet with which I need help.
app.engine('html', require('ejs').renderFile);
exports.profile = function(req, res) {
res.render('profile', { mysql: mysql });
}
I need to be able to use the mysql.createConnection in my profile.ejs file.
Any help would be great.
// server.js
// set up ======================================================================
// get all the tools we need
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var configDB = require('./config/database.js');
var Connection = require('tedious').Connection;
var config = {
userName: 'DESKTOP-S6CM9A9\\Yash',
password: '',
server: 'DESKTOP-S6CM9A9\\SQLEXPRESS',
};
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
var mysql = require('mysql');
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "yashm"
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
var sql="Select * from test.productlist";
con.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
});
});
app.engine('html', require('ejs').renderFile);
exports.profile = function(req, res) {
res.render('profile', { mysql: mysql });
}
//--------------------------------------------------------------------------------
// configuration ===============================================================
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(session({ secret: 'test run' })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
// routes ======================================================================
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
// launch ======================================================================
app.listen(port);
console.log('The magic happens on port ' + port);
Like already said in the comment, you have to do your query logic in your server.js and then pass the data to your view (or maybe even pre-process it!)
exports.profile = function(req, res) {
con.query('SELECT 1', function (error, results, fields) {
if (error) throw error;
// connected!
res.render('profile', { data: results });
});
}
In your ejs you can loop trough the data, and acces the fields as data[i]['fieldname']
<ul>
<% for(var i=0; i<data.length; i++) {%>
<li><%= data[i]['id'] %></li>
<% } %>
</ul>