Exporting a Mongoose connection that becomes available in an async callback? - node.js

I'm new to coding in Node.js and I've created a DB connection through mongoose, then exporting the database object into my main app.js file:
// db.js
var mongoose = require("mongoose");
var uri = /*The URL*/;
var db = mongoose.connect(uri, {
useMongoClient: true
});
exports.db = db;
Here I'm trying to use that DB connection to perform CRUD operations:
// app.js
var db = require('./db');
app.post('/', function (req, res) {
db.collection(/* … */); // throws error
});
The error is:
TypeError: db.collection is not a function
I think this is because that the call of connect in the db.js is asynchronous and the require in app.js is synchronous - so it'll be undefined when I execute db.collection?? How can Mongoose be used to avoid this error?
Goal: I want to be able to call db.collection.insertOne() within my app.js
I found a somewhat related topic but it doesn't use Mongoose, so I'm confused as to how to resolve this issue: How to export an object that only becomes available in an async callback?

Answering my own question:
It'll need a mongoose model in the app.js. So instead of doing db.collection in the main app.js, I ended up routing the CRUD operations to functions defined in the controller file.
//app.js
var app = express();
var router = express.Router();
app.use(router);
require("./Routes")(router);
router.get("/xxx", xxx.get);
Here are the routes:
//routes.js - takes care of routing URLs to the functions
var XXX = require('../xxx');
module.exports = function(router){
router.get('/XXX', XXX.get)
};
Here is the actual function:
//xxx.js - functions defined here
exports.get = function (req, res) {
XXX.getAll(req.body, function(err, result){
if (!err) {
return res.send(result); // Posting all the XXX
} else {
return res.send(err); // 500 error
}
});
};

Related

Passing a mysql connection to expression routing middleware function as argument

I am wondering if I can pass a connected database instance to an express middleware as an argument.
For example:
// in app.js
const mysql = require('mysql');
const mysqlCon = mysql.createConnection({
// some configurations...
})
mysqlCon.connect((err)=> if(err) throw err);
then in a separate file...
// in a separate file called: login handler
const loginHandler = (req, res, dbCon) => {
// query database and stuff...
}
module.exports = loginHanlder;
then back in app.js passes the established mysql connection into the middleware handler
// back in app.js
// a route
const loginHandler = require('./handlers/loginHanlder.js');
app.get('/login', loginHanlder(req, res, mysqlCon));
Will this work? Or are there a conventionally better way of achieving this goal?
The way you're trying to do it won't work, as req,res will be undefined.
However, you could create a factory function that takes the connection as a parameter and retours a route-handler function. Since the function that will be returned is a closure, it will have access to the db-connection in the parent scope. Something like:
function getRequestHandler(dbConn) {
return function (req, res, next) {
// use dbConn here to do stuff
}
}
You can use it like this:
const dbConn = initConnection(); // connect to your db here and return the connection instance
app.get('/login', getRequestHandler(dbConn));
Alternatively, if you don't want/need to create your own factory function, you can simply do:
app.get('/login', (req, res) => loginHandler(req, res, mysqlCon));

is there a way to create a separate file for mongodb operation functions and use those functions in index file?

i have main code in index.js file with express server, and i want to create another file just to handle database CRUD operations. How can i do the following?
index.js
import functions from mongo.js
getUsers()
mongo.js
using MongoClient.connect to connect to db
function getUser(){
// get users from mongo db
}
You can achieve this creating helper function:
I will explain on example from my project:
First you need to create your helper function file
helper.js
module.exports = {
userAuthenticated: function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.redirect('/login')
}
};
As you can see I exported this function.
Then we are able to reach the code from it like this in other .js files:
other.js
const {userAuthenticated} = require('../../helpers/authentication.js');
router.all('/*', userAuthenticated, (req, res, next)=>{
req.app.locals.layout = 'admin';
next();
});
Do you use mongoose? I strictly recommend to use this lib instead of native connection driver.
You could achieve your goal by creating mongoose connection in a separate file, then import connection instance to the file with db schema. For example:
const mongoose = require("./mongo");
const Schema = mongoose.Schema;
const User = new Schema({
name: { type: String },
password: { type: String })
const UserModel = mongoose.model("User",User);
module.exports = {
model: UserModel,
getById: id => UserModel.find({_id:id})
}
And then just import those file in the place where you want to use it:
const UserModel = require("./User");
...
UserModel.getById("someid").then(handler);

Fail to retrieve data from MongoDb on Node.Js API

I have a MongoDb server hosted on Azure. I'm now building a Node.js API meant to retrieve data from a table on one of the databases (i.e. table: Word; database: MyDatabase). I've built the API following this tutorial, but I'm unable to successfully retrieve any data from it...
I know the server is up and running and also reachable since I can tcp-connect to it through:
psping [Azure's Public IP]:27017
Now, I have an node.js api with the following code:
1) app/server.js
var express = require('express'); // call express
var app = express(); // define our app using express
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
mongoose.connect('mongodb://[Azure's public IP]:27017/MyDatabase');
var Word = require('./models/word');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var port = process.env.PORT || 8080; // set our port
// ROUTES FOR API
var router = express.Router(); // get an instance of the express Router
// middleware to use for all requests
router.use(function(req, res, next) {
// do logging
console.log('Something is happening.');
next();
});
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
router.route('/words')
.get(function(req, res) {
Word.find(function(err, words) {
if (err)
res.send(err);
res.json(words);
});
});
// more routes for our API will happen here
// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);
// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);
I've also written a model for my only table within the database, which has 3 columns: the auto-generated ObjectId, Spanish, French (meant to have words in both languages to make it work as a translator). The models looks like this: 2) app/models/word.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var WordSchema = new Schema({
spanish: String,
french: String
})
var Word = mongoose.model('Word',WordSchema);
module.exports = Word;
Now, I go to postman and GET on the following: http://localhost:8080/api/words; which returns [].
On MongoDb logs I see the following:
2016-08-05T03:16:26.520+0000 I NETWORK [conn60] end connection [Some IP]:[Some port] (1 connections now open)
2016-08-05T03:31:11.878+0000 I NETWORK [initandlisten] connection accepted from [Some IP]:[Some port] #61 (1 connection now open)
As you mentioned in your comment that the documents were retrieved from db.word.find() I think I found the problem. You need to put documents into collection named words, instead of word.
Mongoose will use the plural version of your model name. See http://mongoosejs.com/docs/models.html for more information.
I think you are missing {} when doing find.
router.route('/words')
.get(function(req, res) {
Word.find({}, //Added here.
function(err, words) {
if (err)
res.send(err);
console.log(words)
res.json(words);
});
});
Hope this will help.
EDIT:-
According the document of doc, the find function accept the first parameter as an object and treat it as conditions, but not a callback function.

How to keep a persistent connection to my mongo instance with express router

I have a express router such as:
var express = require('express')
, router = express.Router()
, bodyParser = require('body-parser')
, mongoclient = require('mongodb').MongoClient
, dbconfig = require('../assets/config.db.json');
router.use( bodyParser.json() );
router.use(bodyParser.urlencoded({
extended: true
}));
router.post('/api/search', (req, res, next) => {
var term = req.body.searchTerm;
mongoclient.connect(dbconfig.url, (err, db) => {
db.accessDatabase(term, (err, result) => {
db.close();
if (err) res.json({result: err});
res.json(result);
});
});
});
module.exports = router;
I have have read that if there is a lot of overhead to make a connection to my db each REST call then I need to make a persistent connection for someone using this REST API. What is the proper way to do this within my router? Right now each time a post request is received it will open a connection, access the db and then close the connection.
EDIT: for clarity I used db.accessDatabase(), but this is not the actual syntax being used within my code.
You open do MongoClient.connect once when your app boots up and reuse the db object. It's not a singleton connection pool each .connect creates a new connection pool.
From node-mongodb-native
Personally, i do it like this
var params = {/*config, etc... required to bootstrap models */}
require('./app/models')(params)
.then(afterModels)
.then(startServer)
function afterModels(theModels) {
params.models = theModels
let providers = require('./app/providers')(params)
params.providers = providers
// boot strap routes
require('./app/routes')(params)
// controllers can use params which has models (db object,e tc.. inside)
}
function startServer() {}

Express4 app.get don't wait library call for continue

I have an express 4 node application with following.
My problem is app.get don't wait to finish exectuion of getAllFsRiver and return nothing.
How to do this?
in app.js
var api1 = require('./routes/api1.js');
app.use(api1) ;
in route/api1.js
*jslint node: true */
'use strict';
var express = require('express');
module.exports = express();
var app = module.exports;
var esclient = require('../lib/esclient') ;
/* GET api vers 1 . */
app.get('/api/1/settings/rivers/fs*', function (req, res) {
var allriver = esclient.getAllFsRiver() ;
console.log("route");
res.json(allriver);
Here res.json is called before esclient.getAllFsRiver has finish execution
My guess is that getAllFsRiver is asynchronous and probably takes a callback. You should pass a callback to the function and handle the response within the callback.
esclient.getAllFsRiver(function (err, json) {
if (err) {
return res.status(500).end();
}
res.json(json);
});
Sorry, I can't add comment. Could you add getAllFsRiver implementation to the question? Maybe it is an async call.
You have must write you route kind of:
*jslint node: true */
'use strict';
var express = require('express');
var router = express.Router();
router.get('/api/1/settings/rivers/fs*', function (req, res) {
var allriver = esclient.getAllFsRiver() ;
console.log("route");
res.json(allriver);
/* ... */
})
module.exports = router;
In you code you exporting from you route new express app, that wrong
adding a callback ti my function. Ok

Resources