I'm using mysql-orm in a Nodejs Express app this is my code:
app.js:
// ... all variables are initialized
var orm = null;
var app = express();
db.create(dbSchema, dbSeeds, dbOptions, function(err, ormObject) {
if (err) throw err;
orm = ormObject;
});
var coursesRoutes = require('./routes/dashboard/courses')(orm);
app.use('/dashboard/courses', coursesRoutes);
/routes/dashboard/courses.js:
var express = require('express');
var router = express.Router();
module.exports = function(orm) {
router.get('/listall', function(req, res, next) {
orm.loadMany('sections', null, function(err, sections) {
if (err) throw err;
res.jsonp(sections);
});
});
return router;
};
And this returns this error:
TypeError: Cannot read property 'loadMany' of null
I know that the problem is that orm variable is passed to file before it is initialized in the db.create callback but I don't know how to solve this.
I tried to put:
var coursesRoutes = require('./routes/dashboard/courses')(orm);
app.use('/dashboard/courses', coursesRoutes);
inside the callback but it returns 404 not found
Your courses function is getting called before db connection is established.
This should do the trick.
var orm = null;
var app = express();
db.create(dbSchema, dbSeeds, dbOptions, function(err, ormObject) {
if (err) throw err;
orm = ormObject;
var coursesRoutes = require('./routes/dashboard/courses')(orm);
app.use('/dashboard/courses', coursesRoutes);
});
Related
I am trying to learn node.js with mongoose. Simply want to read from database and display result in a browser. I have index.js where I compiled model from schema as
var mlink = mongoose.model('mlink',mlinkSchema)
Then I exported it so as to use it in server.js file as
module.exports = mongoose.model('mlink',mlinkschema);
Under server.js, I require it as
const mlink = require(__dirname, "../Scripts/index.js");
And now, I am using express router as below
const express = require('express');
const app = express();
const router = express.Router();
app.use("/", router);
router.route("/Scripts").get(function(req,res){
mlink.find({},function(err, result){
if (err) {
res.send(err);
}
else {
res.send(result);
}
});
});
Here I keep on getting error as mlink.find is not a function. Please help I am stuck.
Instead of this
module.exports = mongoose.model('mlink',mlinkschema);
It should be
module.exports = mlink;
If you have a correct model than
module.exports = mongoose.model('mlink',mlinkSchema);
should work (you had a typo in mlinkSchema it needs to have a capital S)
You would import a model like this:
const mlink = mongoose.model("mlink");
Getting data from MongoDB is time consuming it should be an asynchronous function
router.route("/Scripts").get(async function(req,res){
await mlink.find({},function(err, result){
if (err) {
res.send(err);
}
else {
res.send(result);
}
});
I'm building a pretty simple API to do a basic CRUD operations on a local mongo database. The code looks fine for me but somehow the CRUD operations results on a pending request which never ends.
Here the parts of the code:
spawn.model.js (Model corresponding to database collection)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var SpawnSchema = Schema({
Name: {
type: String,
unique: false,
required: true
}
}, { timestamps: true });
module.exports = mongoose.model('spawns', SpawnSchema);
spawn.controller.js
var Spawn = require('../models/Spawn/spawn.model');
exports.getSpawns = function(req, res){
Spawn.find({}, function(spawns){
res.send(spawns);
});
}
Here the spawn.routes.js file:
var Spawns = require('../controllers/spawn.controller');
module.exports = function(app){
app.get('/list', Spawns.getSpawns);
}
And then finally the server.js file:
var express = require('express');
var bodyParser = require('body-parser');
var properties = require('./config/properties');
var db = require('./config/database');
var app = express();
//configure bodyparser
var bodyParserJSON = bodyParser.json();
var bodyParserURLEncoded = bodyParser.urlencoded({ extended: true });
// call the database connectivity function
db();
// configure app.use()
app.use(bodyParserJSON);
app.use(bodyParserURLEncoded);
// Routes
app.get('/', function(req, res){
res.json({ message: 'Spawns API' });
});
require('./app/routes/spawn.routes')(app);
// intialise server
app.listen(properties.PORT, () => {
console.log(`Server is running on ${properties.PORT} port.`);
})
The database file on ./config is the following:
var mongoose = require('mongoose');
var dbURL = require('./properties').DB;
mongoose.Promise = global.Promise;
module.exports = function(){
mongoose.connect(dbURL, { useNewUrlParser: true }, function(){
console.log('Successfully connected to database');
});
}
And the properties.js on /config is simply an object with the database URL and the port for the express server.
When I try to to a request through Postman to the URL: http://localhost:4000/list the request gets hanged and never resolves. What am I missing?
PD: SOLVED!
===========
I needed to update mongoose version on npm cause it was 3.x and needed to be 5.x in order to work well with the new methods.
Update your code little bit, Like this and check
spwanRoute.js
const express = require('express');
const router = express.Router();
const spawnCntr = require('./speanControllers');
router.get('/list', spawnCntr.getSpawns);
module.exports = router;
spwanUtils.js
const Spawns = require('../models/Spawn/spawn.dao');
const spawnUtils = {};
spawnUtils.getSpawns = (req, res) => {
try {
Spawns.get({}, (err, spawns) => {
if(err){
return res.status(400).json({ error: err });
}
return res.status(200).json({ spawns });
});
} catch (err) {
console.log(err);
return res.status(500).json({ error: 'INTERNAL_EROR' });
}
}
module.exports = spawnUtils;
I am having problems trying to access the "DB" database object that is created when the MongoDB client module connects to my MongoDB database.
At the moment I am getting an error stating that, within data.js, 'db' is not defined. I understand why this is - the db object is not being "passed" through to the router and then subsequently through to the controller.
What is the best way to do this?
I have tried to pass the "db" object through to the router (dataRoutes.js) but I cannot figure how to make this accessible to the controller (data.js). Could someone please help?
Please note I have not included the other routes and controllers but they simply submit a Form via the POST method to /data/submit . The controller below is meant to write this form data to the MongoDB database.
Here is the relevant code:
app.js
var express = require('express');
var path = require('path')
var MongoClient = require('mongodb').MongoClient;
var bodyParser = require('body-parser');
var app = express();
var routes = require('./routes/index');
var dataRoutes = require('./routes/dataRoutes');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
MongoClient.connect("mongodb://localhost:27017/m101", function(err, db) {
if(err) throw err;
console.log("Successfully connected to MongoDB.");
app.use('/', routes); // Use normal routes for wesbite
app.use('/data', dataRoutes);
app.get('/favicon.ico', function(req, res) {
res.send(204);
});
app.use(function(req, res, next) {
var err = new Error('Oops Page/Resource Not Found!');
err.status = 404;
next(err); //Proceed to next middleware
});
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
// update the error responce, either with the error status
// or if that is falsey use error code 500
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
app.use(function(err, req, res, next) {
console.log('Error');
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
var server = app.listen(3000, function() {
var port = server.address().port;
console.log("Express server listening on port %s.", port);
});
});
dataRoutes.js
// router
var express = require('express');
var router = express.Router();
// controller references
var ctrlsData = require('../controllers/data');
router.post('/submit', ctrlsData.submit);
module.exports = router;
data.js
var MongoClient = require('mongodb').MongoClient;
var sendJsonResponse = function(res, status, content) {
res.status(status);
res.json(content);
};
module.exports.submit = function(req, res) {
var title = req.body.title;
var year = req.body.year;
var imdb = req.body.imdb;
/*
console.log('submitted');
console.log(req.body);
sendJsonResponse(res, 201, {title,year,imdb});
*/
var title = req.body.title;
var year = req.body.year;
var imdb = req.body.imdb;
if ((title == '') || (year == '') || (imdb == '')) {
sendJsonResponse(res, 404, {
"message": "Title, Year and IMDB Reference are all required."
});
} else {
db.collection('movies').insertOne(
{ 'title': title, 'year': year, 'imdb': imdb },
function (err, r) {
if (err) {
sendJsonResponse(res, 400, err);
} else {
sendJsonResponse(res, 201, "Document inserted with _id: " + r.insertedId + {title,year,imdb});
}
}
);
}
};
Create a db variable that reference mongodb in app.js :
MongoClient.connect("mongodb://localhost:27017/m101", function(err, db) {
app.db = db;
//.....
});
In data.js, access db from req.app :
module.exports.submit = function(req, res) {
req.app.db.collection('movies').insertOne({ 'title': title, 'year': year, 'imdb': imdb },
function(err, r) {}
)
};
The accepted answer isn't quite correct. You shouldn't attach custom objects to the app object. That's what app.locals is for. Plus, the accepted answer will fail when using Typescript.
app.locals.db = db;
router.get('/foo', (req) => {
req.app.locals.db.insert('bar');
});
Sure, it's longer. But you get the assurance that future updates to ExpressJS will not interfere with your object.
I understand that the answer of #Bertrand is functional, but it is not usually recommended. The reason being that, from a software point of view, you should have a better separation in your software.
app.js
var express = require('express');
var path = require('path')
var MongoClient = require('mongodb').MongoClient;
var bodyParser = require('body-parser');
var app = express();
var routes = require('./routes/index');
var dataRoutes = require('./routes/dataRoutes');
var DB = require('./db.js');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
DB.Init("mongodb://localhost:27017/m101")
.then(() => {
console.log("Successfully connected to MongoDB.");
app.use('/', routes); // Use normal routes for wesbite
app.use('/data', dataRoutes);
app.get('/favicon.ico', function(req, res) {
res.send(204);
});
var server = app.listen(3000, function() {
var port = server.address().port;
console.log("Express server listening on port %s.", port);
});
})
.catch((e) => {
console.log("Error initializing db");
});
db.js
var _db = null;
module.exports = {
Init: (url) => {
return new Promise((resolve, reject) => {
if (!url)
reject("You should provide a URL");
MongoClient.connect("mongodb://localhost:27017/m101", function(err, db) {
if(err) reject(err);
_db = db;
resolve(); // Or resolve(db) if you wanna return the db object
});
});
},
Submit: (req, res, next) => {
// Whatever goes. You have access to _db here, too!
}
};
in data.js
var DB = require('../db.js');
router.post('/submit', DB.submit);
Finally, even this answer can be improved as you are not usually advised to wait for the DB to connect, otherwise, you are losing the advantage of using ASync procs.
Consider something similar to here in app.js:
Promise.resolve()
.then(() => {
// Whatever DB stuff are
// DB.Init ?
})
.then(() => {
// Someone needs routing?
})
...
.catch((e) => {
console.error("Ther app failed to start");
console.error(e);
});
I understand that in the last sample, you can not instantly query DB as it may not have connected yet, but this is a server, and users are usually expected to wait for your DB to init. However, if you wanna more proof solution, consider implementing something yourself in DB.submit to wait for the connect. Or, you can also use something like mongoose.
I know there are lots of questions similar to mine but I could not find the best solution.
I am creating a web app with node and rethinkdb. I want to organise different js files (modules) so that each has specific task.
I have this query.js file whose query result must be passed to routes.js file.
I have tried implement this in the following way.
query.js
//dependencies
var express = require('express');
var path = require('path');
var r = require('rethinkdbdash')({
port: 28015,
host: 'localhost',
db: 'stocks'
});
var len;
//function to get companies list
exports.clist = function(){
r.table('company')
.run()
.then(function(response){
return response;
})
.error(function(err){
console.log(err);
})
}
console.log(exports.clist[0].id)
//function to get number of entries in database
exports.clen = function(){
r.table('company')
.run()
.then(function(response){
len = Object.keys(clist).length;
return len;
})
.error(function(err){
console.log(err);
})
}
routes.js
//dependencies
var express = require('express');
var request = require('request');
var path = require('path');
var r = require('rethinkdbdash')({
port: 28015,
host: 'localhost',
db: 'stocks'
});
//query module
var query = require('./query')
clist = query.clist();
clen = query.clen();
//create router object
var router = express.Router();
//export router
module.exports = router;
//home page
router.get('/', function(req, res) {
console.log('served homepage');
res.render('pages/home');
});
//--companies page--//
router.get('/company', function(req,res){
console.log('served companies page')
res.render('pages/company', {
clist: clist,
x:clen
});
});
the console log in query.js is showing that cannot read property id of undefined.
Also I would like to know is there a way to directly pass the variables instead of using functions and then calling it.
I apologise if the solution is obvious.
To summarise I want the query result which is an object to be accessible from routes.js file.
Note: As exports.clist1 is an asynchronous method, you can't expect the result to be printed in the next line, hence comment this line and follow as below
//console.log(exports.clist[0].id)
You have to register a middleware to make this working, otherwise, query will be called only at the time of express server started and not at every request.
So you can do like this,
Hope you had something like this in your startup file (app.js),
var app = module.exports = express();
routes.js
//query module
var query = require('./query')
var app = require('../app'); // this should resolve to your app.js file said above
//clist = query.clist();
//clen = query.clen();
// middleware to populate clist & clen
app.use(function(req, res, next){
query.companyList(function(err, data){
if(!err) {
req.clist = data.clist;
req.clen= data.clen;
}
next();
});
});
query.companyList(function(err, data){
if(err) {
console.log(err);
} else {
console.log(data.clist[0].id);
console.dir(data.clist);
}
});
//create router object
var router = express.Router();
//export router
module.exports = router;
//home page
router.get('/', function(req, res) {
console.log('served homepage');
res.render('pages/home');
});
//--companies page--//
router.get('/company', function(req,res){
console.log('served companies page')
res.render('pages/company', {
clist: req.clist,
x: req.clen
});
});
Change your query.js like this,
//function to get companies list
exports.companyList = function(next){
r.table('company')
.run()
.then(function(response){
var list = {
clist: response,
clen: Object.keys(response).length
};
next(null, list);
})
.error(function(err){
console.log(err);
next(err);
})
};
I am trying to implement a search functionality for my app. I have an express route to get incoming search terms.
Here is the entirety of my router file:
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
var searchutil = require('../utils/searchhandler');
router.use( bodyParser.json() );
router.use(bodyParser.urlencoded({
extended: true
}));
router.post('/api/search', (req, res, next) => {
var term = req.body.searchTerm;
console.log(term);
searchutil();
res.json({test: 'post received'});
});
module.exports = router;
And here is my searchhandler file which is being including in my router:
var fs = require('fs');
var findResults = function() {
var items = fs.readFile('./server/assets/items.json', 'utf8', (err, data) =>{
if (err) throw err;
console.log(JSON.parse(data));
return JSON.parse(data);
});
}
module.exports = findResults;
This is all working just fine and dandy. it basically just prints out the contents of './server/assets/items.json' on the server when a post request route of '/api/search' is hit. The question I had was about using the json file within my router file. Say my router file was:
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
var fs = require('fs');
var items = fs.readFile('./server/assets/items.json', 'utf8', (err, data) =>{
if (err) throw err;
console.log(JSON.parse(data));
return JSON.parse(data);
});
router.use( bodyParser.json() );
router.use(bodyParser.urlencoded({
extended: true
}));
router.post('/api/search', (req, res, next) => {
var term = req.body.searchTerm;
console.log(term);
console.log(items);
res.json({test: 'post received'});
});
module.exports = router;
So now my router file is getting the file asset and trying to print it out within my router.post('/api/search', ...); function. The problem that occurs is that when it attempts to print it in that function items appears to be undefined, but the print from within the fs.readFile(); correctly logs the contents of the file. I think this is some sort of scope issue I am running into with JS, but I am not sure how to explain it to myself so I thought I'd ask it here why it is working one way, but not the other.
You should use a callback:
var getItems = function(cb) {
fs.readFile('./server/assets/items.json', 'utf8', (err, data) {
if (err) cb({error: err});
console.log(JSON.parse(data));
cb({items: JSON.parse(data)});
});
};
And then change the route to:
router.post('/api/search', (req, res, next) => {
var term = req.body.searchTerm;
console.log(term);
getItems(function (cb) {
if (!cb.error) {
console.log(cb.items);
res.json({test: 'post received'});
}
});
});